1 /* 2 Defines the basic matrix operations for the AIJ (compressed row) 3 matrix storage format. 4 */ 5 6 #include <../src/mat/impls/aij/seq/aij.h> /*I "petscmat.h" I*/ 7 #include <petscblaslapack.h> 8 #include <petscbt.h> 9 #include <petsc/private/kernels/blocktranspose.h> 10 11 PetscErrorCode MatSeqAIJSetTypeFromOptions(Mat A) 12 { 13 PetscBool flg; 14 char type[256]; 15 16 PetscFunctionBegin; 17 PetscObjectOptionsBegin((PetscObject)A); 18 PetscCall(PetscOptionsFList("-mat_seqaij_type", "Matrix SeqAIJ type", "MatSeqAIJSetType", MatSeqAIJList, "seqaij", type, 256, &flg)); 19 if (flg) PetscCall(MatSeqAIJSetType(A, type)); 20 PetscOptionsEnd(); 21 PetscFunctionReturn(PETSC_SUCCESS); 22 } 23 24 PetscErrorCode MatGetColumnReductions_SeqAIJ(Mat A, PetscInt type, PetscReal *reductions) 25 { 26 PetscInt i, m, n; 27 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 28 29 PetscFunctionBegin; 30 PetscCall(MatGetSize(A, &m, &n)); 31 PetscCall(PetscArrayzero(reductions, n)); 32 if (type == NORM_2) { 33 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscAbsScalar(aij->a[i] * aij->a[i]); 34 } else if (type == NORM_1) { 35 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscAbsScalar(aij->a[i]); 36 } else if (type == NORM_INFINITY) { 37 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] = PetscMax(PetscAbsScalar(aij->a[i]), reductions[aij->j[i]]); 38 } else if (type == REDUCTION_SUM_REALPART || type == REDUCTION_MEAN_REALPART) { 39 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscRealPart(aij->a[i]); 40 } else if (type == REDUCTION_SUM_IMAGINARYPART || type == REDUCTION_MEAN_IMAGINARYPART) { 41 for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscImaginaryPart(aij->a[i]); 42 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown reduction type"); 43 44 if (type == NORM_2) { 45 for (i = 0; i < n; i++) reductions[i] = PetscSqrtReal(reductions[i]); 46 } else if (type == REDUCTION_MEAN_REALPART || type == REDUCTION_MEAN_IMAGINARYPART) { 47 for (i = 0; i < n; i++) reductions[i] /= m; 48 } 49 PetscFunctionReturn(PETSC_SUCCESS); 50 } 51 52 PetscErrorCode MatFindOffBlockDiagonalEntries_SeqAIJ(Mat A, IS *is) 53 { 54 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 55 PetscInt i, m = A->rmap->n, cnt = 0, bs = A->rmap->bs; 56 const PetscInt *jj = a->j, *ii = a->i; 57 PetscInt *rows; 58 59 PetscFunctionBegin; 60 for (i = 0; i < m; i++) { 61 if ((ii[i] != ii[i + 1]) && ((jj[ii[i]] < bs * (i / bs)) || (jj[ii[i + 1] - 1] > bs * ((i + bs) / bs) - 1))) cnt++; 62 } 63 PetscCall(PetscMalloc1(cnt, &rows)); 64 cnt = 0; 65 for (i = 0; i < m; i++) { 66 if ((ii[i] != ii[i + 1]) && ((jj[ii[i]] < bs * (i / bs)) || (jj[ii[i + 1] - 1] > bs * ((i + bs) / bs) - 1))) { 67 rows[cnt] = i; 68 cnt++; 69 } 70 } 71 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cnt, rows, PETSC_OWN_POINTER, is)); 72 PetscFunctionReturn(PETSC_SUCCESS); 73 } 74 75 PetscErrorCode MatFindZeroDiagonals_SeqAIJ_Private(Mat A, PetscInt *nrows, PetscInt **zrows) 76 { 77 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 78 const MatScalar *aa; 79 PetscInt i, m = A->rmap->n, cnt = 0; 80 const PetscInt *ii = a->i, *jj = a->j, *diag; 81 PetscInt *rows; 82 83 PetscFunctionBegin; 84 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 85 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 86 diag = a->diag; 87 for (i = 0; i < m; i++) { 88 if ((diag[i] >= ii[i + 1]) || (jj[diag[i]] != i) || (aa[diag[i]] == 0.0)) cnt++; 89 } 90 PetscCall(PetscMalloc1(cnt, &rows)); 91 cnt = 0; 92 for (i = 0; i < m; i++) { 93 if ((diag[i] >= ii[i + 1]) || (jj[diag[i]] != i) || (aa[diag[i]] == 0.0)) rows[cnt++] = i; 94 } 95 *nrows = cnt; 96 *zrows = rows; 97 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 98 PetscFunctionReturn(PETSC_SUCCESS); 99 } 100 101 PetscErrorCode MatFindZeroDiagonals_SeqAIJ(Mat A, IS *zrows) 102 { 103 PetscInt nrows, *rows; 104 105 PetscFunctionBegin; 106 *zrows = NULL; 107 PetscCall(MatFindZeroDiagonals_SeqAIJ_Private(A, &nrows, &rows)); 108 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrows, rows, PETSC_OWN_POINTER, zrows)); 109 PetscFunctionReturn(PETSC_SUCCESS); 110 } 111 112 PetscErrorCode MatFindNonzeroRows_SeqAIJ(Mat A, IS *keptrows) 113 { 114 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 115 const MatScalar *aa; 116 PetscInt m = A->rmap->n, cnt = 0; 117 const PetscInt *ii; 118 PetscInt n, i, j, *rows; 119 120 PetscFunctionBegin; 121 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 122 *keptrows = NULL; 123 ii = a->i; 124 for (i = 0; i < m; i++) { 125 n = ii[i + 1] - ii[i]; 126 if (!n) { 127 cnt++; 128 goto ok1; 129 } 130 for (j = ii[i]; j < ii[i + 1]; j++) { 131 if (aa[j] != 0.0) goto ok1; 132 } 133 cnt++; 134 ok1:; 135 } 136 if (!cnt) { 137 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 138 PetscFunctionReturn(PETSC_SUCCESS); 139 } 140 PetscCall(PetscMalloc1(A->rmap->n - cnt, &rows)); 141 cnt = 0; 142 for (i = 0; i < m; i++) { 143 n = ii[i + 1] - ii[i]; 144 if (!n) continue; 145 for (j = ii[i]; j < ii[i + 1]; j++) { 146 if (aa[j] != 0.0) { 147 rows[cnt++] = i; 148 break; 149 } 150 } 151 } 152 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 153 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cnt, rows, PETSC_OWN_POINTER, keptrows)); 154 PetscFunctionReturn(PETSC_SUCCESS); 155 } 156 157 PetscErrorCode MatDiagonalSet_SeqAIJ(Mat Y, Vec D, InsertMode is) 158 { 159 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)Y->data; 160 PetscInt i, m = Y->rmap->n; 161 const PetscInt *diag; 162 MatScalar *aa; 163 const PetscScalar *v; 164 PetscBool missing; 165 166 PetscFunctionBegin; 167 if (Y->assembled) { 168 PetscCall(MatMissingDiagonal_SeqAIJ(Y, &missing, NULL)); 169 if (!missing) { 170 diag = aij->diag; 171 PetscCall(VecGetArrayRead(D, &v)); 172 PetscCall(MatSeqAIJGetArray(Y, &aa)); 173 if (is == INSERT_VALUES) { 174 for (i = 0; i < m; i++) aa[diag[i]] = v[i]; 175 } else { 176 for (i = 0; i < m; i++) aa[diag[i]] += v[i]; 177 } 178 PetscCall(MatSeqAIJRestoreArray(Y, &aa)); 179 PetscCall(VecRestoreArrayRead(D, &v)); 180 PetscFunctionReturn(PETSC_SUCCESS); 181 } 182 PetscCall(MatSeqAIJInvalidateDiagonal(Y)); 183 } 184 PetscCall(MatDiagonalSet_Default(Y, D, is)); 185 PetscFunctionReturn(PETSC_SUCCESS); 186 } 187 188 PetscErrorCode MatGetRowIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *m, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 189 { 190 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 191 PetscInt i, ishift; 192 193 PetscFunctionBegin; 194 if (m) *m = A->rmap->n; 195 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 196 ishift = 0; 197 if (symmetric && A->structurally_symmetric != PETSC_BOOL3_TRUE) { 198 PetscCall(MatToSymmetricIJ_SeqAIJ(A->rmap->n, a->i, a->j, PETSC_TRUE, ishift, oshift, (PetscInt **)ia, (PetscInt **)ja)); 199 } else if (oshift == 1) { 200 PetscInt *tia; 201 PetscInt nz = a->i[A->rmap->n]; 202 /* malloc space and add 1 to i and j indices */ 203 PetscCall(PetscMalloc1(A->rmap->n + 1, &tia)); 204 for (i = 0; i < A->rmap->n + 1; i++) tia[i] = a->i[i] + 1; 205 *ia = tia; 206 if (ja) { 207 PetscInt *tja; 208 PetscCall(PetscMalloc1(nz + 1, &tja)); 209 for (i = 0; i < nz; i++) tja[i] = a->j[i] + 1; 210 *ja = tja; 211 } 212 } else { 213 *ia = a->i; 214 if (ja) *ja = a->j; 215 } 216 PetscFunctionReturn(PETSC_SUCCESS); 217 } 218 219 PetscErrorCode MatRestoreRowIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 220 { 221 PetscFunctionBegin; 222 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 223 if ((symmetric && A->structurally_symmetric != PETSC_BOOL3_TRUE) || oshift == 1) { 224 PetscCall(PetscFree(*ia)); 225 if (ja) PetscCall(PetscFree(*ja)); 226 } 227 PetscFunctionReturn(PETSC_SUCCESS); 228 } 229 230 PetscErrorCode MatGetColumnIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *nn, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 231 { 232 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 233 PetscInt i, *collengths, *cia, *cja, n = A->cmap->n, m = A->rmap->n; 234 PetscInt nz = a->i[m], row, *jj, mr, col; 235 236 PetscFunctionBegin; 237 *nn = n; 238 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 239 if (symmetric) { 240 PetscCall(MatToSymmetricIJ_SeqAIJ(A->rmap->n, a->i, a->j, PETSC_TRUE, 0, oshift, (PetscInt **)ia, (PetscInt **)ja)); 241 } else { 242 PetscCall(PetscCalloc1(n, &collengths)); 243 PetscCall(PetscMalloc1(n + 1, &cia)); 244 PetscCall(PetscMalloc1(nz, &cja)); 245 jj = a->j; 246 for (i = 0; i < nz; i++) collengths[jj[i]]++; 247 cia[0] = oshift; 248 for (i = 0; i < n; i++) cia[i + 1] = cia[i] + collengths[i]; 249 PetscCall(PetscArrayzero(collengths, n)); 250 jj = a->j; 251 for (row = 0; row < m; row++) { 252 mr = a->i[row + 1] - a->i[row]; 253 for (i = 0; i < mr; i++) { 254 col = *jj++; 255 256 cja[cia[col] + collengths[col]++ - oshift] = row + oshift; 257 } 258 } 259 PetscCall(PetscFree(collengths)); 260 *ia = cia; 261 *ja = cja; 262 } 263 PetscFunctionReturn(PETSC_SUCCESS); 264 } 265 266 PetscErrorCode MatRestoreColumnIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done) 267 { 268 PetscFunctionBegin; 269 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 270 271 PetscCall(PetscFree(*ia)); 272 PetscCall(PetscFree(*ja)); 273 PetscFunctionReturn(PETSC_SUCCESS); 274 } 275 276 /* 277 MatGetColumnIJ_SeqAIJ_Color() and MatRestoreColumnIJ_SeqAIJ_Color() are customized from 278 MatGetColumnIJ_SeqAIJ() and MatRestoreColumnIJ_SeqAIJ() by adding an output 279 spidx[], index of a->a, to be used in MatTransposeColoringCreate_SeqAIJ() and MatFDColoringCreate_SeqXAIJ() 280 */ 281 PetscErrorCode MatGetColumnIJ_SeqAIJ_Color(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *nn, const PetscInt *ia[], const PetscInt *ja[], PetscInt *spidx[], PetscBool *done) 282 { 283 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 284 PetscInt i, *collengths, *cia, *cja, n = A->cmap->n, m = A->rmap->n; 285 PetscInt nz = a->i[m], row, mr, col, tmp; 286 PetscInt *cspidx; 287 const PetscInt *jj; 288 289 PetscFunctionBegin; 290 *nn = n; 291 if (!ia) PetscFunctionReturn(PETSC_SUCCESS); 292 293 PetscCall(PetscCalloc1(n, &collengths)); 294 PetscCall(PetscMalloc1(n + 1, &cia)); 295 PetscCall(PetscMalloc1(nz, &cja)); 296 PetscCall(PetscMalloc1(nz, &cspidx)); 297 jj = a->j; 298 for (i = 0; i < nz; i++) collengths[jj[i]]++; 299 cia[0] = oshift; 300 for (i = 0; i < n; i++) cia[i + 1] = cia[i] + collengths[i]; 301 PetscCall(PetscArrayzero(collengths, n)); 302 jj = a->j; 303 for (row = 0; row < m; row++) { 304 mr = a->i[row + 1] - a->i[row]; 305 for (i = 0; i < mr; i++) { 306 col = *jj++; 307 tmp = cia[col] + collengths[col]++ - oshift; 308 cspidx[tmp] = a->i[row] + i; /* index of a->j */ 309 cja[tmp] = row + oshift; 310 } 311 } 312 PetscCall(PetscFree(collengths)); 313 *ia = cia; 314 *ja = cja; 315 *spidx = cspidx; 316 PetscFunctionReturn(PETSC_SUCCESS); 317 } 318 319 PetscErrorCode MatRestoreColumnIJ_SeqAIJ_Color(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscInt *spidx[], PetscBool *done) 320 { 321 PetscFunctionBegin; 322 PetscCall(MatRestoreColumnIJ_SeqAIJ(A, oshift, symmetric, inodecompressed, n, ia, ja, done)); 323 PetscCall(PetscFree(*spidx)); 324 PetscFunctionReturn(PETSC_SUCCESS); 325 } 326 327 PetscErrorCode MatSetValuesRow_SeqAIJ(Mat A, PetscInt row, const PetscScalar v[]) 328 { 329 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 330 PetscInt *ai = a->i; 331 PetscScalar *aa; 332 333 PetscFunctionBegin; 334 PetscCall(MatSeqAIJGetArray(A, &aa)); 335 PetscCall(PetscArraycpy(aa + ai[row], v, ai[row + 1] - ai[row])); 336 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 337 PetscFunctionReturn(PETSC_SUCCESS); 338 } 339 340 /* 341 MatSeqAIJSetValuesLocalFast - An optimized version of MatSetValuesLocal() for SeqAIJ matrices with several assumptions 342 343 - a single row of values is set with each call 344 - no row or column indices are negative or (in error) larger than the number of rows or columns 345 - the values are always added to the matrix, not set 346 - no new locations are introduced in the nonzero structure of the matrix 347 348 This does NOT assume the global column indices are sorted 349 350 */ 351 352 #include <petsc/private/isimpl.h> 353 PetscErrorCode MatSeqAIJSetValuesLocalFast(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 354 { 355 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 356 PetscInt low, high, t, row, nrow, i, col, l; 357 const PetscInt *rp, *ai = a->i, *ailen = a->ilen, *aj = a->j; 358 PetscInt lastcol = -1; 359 MatScalar *ap, value, *aa; 360 const PetscInt *ridx = A->rmap->mapping->indices, *cidx = A->cmap->mapping->indices; 361 362 PetscFunctionBegin; 363 PetscCall(MatSeqAIJGetArray(A, &aa)); 364 row = ridx[im[0]]; 365 rp = aj + ai[row]; 366 ap = aa + ai[row]; 367 nrow = ailen[row]; 368 low = 0; 369 high = nrow; 370 for (l = 0; l < n; l++) { /* loop over added columns */ 371 col = cidx[in[l]]; 372 value = v[l]; 373 374 if (col <= lastcol) low = 0; 375 else high = nrow; 376 lastcol = col; 377 while (high - low > 5) { 378 t = (low + high) / 2; 379 if (rp[t] > col) high = t; 380 else low = t; 381 } 382 for (i = low; i < high; i++) { 383 if (rp[i] == col) { 384 ap[i] += value; 385 low = i + 1; 386 break; 387 } 388 } 389 } 390 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 391 return PETSC_SUCCESS; 392 } 393 394 PetscErrorCode MatSetValues_SeqAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 395 { 396 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 397 PetscInt *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N; 398 PetscInt *imax = a->imax, *ai = a->i, *ailen = a->ilen; 399 PetscInt *aj = a->j, nonew = a->nonew, lastcol = -1; 400 MatScalar *ap = NULL, value = 0.0, *aa; 401 PetscBool ignorezeroentries = a->ignorezeroentries; 402 PetscBool roworiented = a->roworiented; 403 404 PetscFunctionBegin; 405 PetscCall(MatSeqAIJGetArray(A, &aa)); 406 for (k = 0; k < m; k++) { /* loop over added rows */ 407 row = im[k]; 408 if (row < 0) continue; 409 PetscCheck(row < A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, row, A->rmap->n - 1); 410 rp = aj + ai[row]; 411 if (!A->structure_only) ap = aa + ai[row]; 412 rmax = imax[row]; 413 nrow = ailen[row]; 414 low = 0; 415 high = nrow; 416 for (l = 0; l < n; l++) { /* loop over added columns */ 417 if (in[l] < 0) continue; 418 PetscCheck(in[l] < A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[l], A->cmap->n - 1); 419 col = in[l]; 420 if (v && !A->structure_only) value = roworiented ? v[l + k * n] : v[k + l * m]; 421 if (!A->structure_only && value == 0.0 && ignorezeroentries && is == ADD_VALUES && row != col) continue; 422 423 if (col <= lastcol) low = 0; 424 else high = nrow; 425 lastcol = col; 426 while (high - low > 5) { 427 t = (low + high) / 2; 428 if (rp[t] > col) high = t; 429 else low = t; 430 } 431 for (i = low; i < high; i++) { 432 if (rp[i] > col) break; 433 if (rp[i] == col) { 434 if (!A->structure_only) { 435 if (is == ADD_VALUES) { 436 ap[i] += value; 437 (void)PetscLogFlops(1.0); 438 } else ap[i] = value; 439 } 440 low = i + 1; 441 goto noinsert; 442 } 443 } 444 if (value == 0.0 && ignorezeroentries && row != col) goto noinsert; 445 if (nonew == 1) goto noinsert; 446 PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at (%" PetscInt_FMT ",%" PetscInt_FMT ") in the matrix", row, col); 447 if (A->structure_only) { 448 MatSeqXAIJReallocateAIJ_structure_only(A, A->rmap->n, 1, nrow, row, col, rmax, ai, aj, rp, imax, nonew, MatScalar); 449 } else { 450 MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar); 451 } 452 N = nrow++ - 1; 453 a->nz++; 454 high++; 455 /* shift up all the later entries in this row */ 456 PetscCall(PetscArraymove(rp + i + 1, rp + i, N - i + 1)); 457 rp[i] = col; 458 if (!A->structure_only) { 459 PetscCall(PetscArraymove(ap + i + 1, ap + i, N - i + 1)); 460 ap[i] = value; 461 } 462 low = i + 1; 463 A->nonzerostate++; 464 noinsert:; 465 } 466 ailen[row] = nrow; 467 } 468 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 469 PetscFunctionReturn(PETSC_SUCCESS); 470 } 471 472 PetscErrorCode MatSetValues_SeqAIJ_SortedFullNoPreallocation(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 473 { 474 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 475 PetscInt *rp, k, row; 476 PetscInt *ai = a->i; 477 PetscInt *aj = a->j; 478 MatScalar *aa, *ap; 479 480 PetscFunctionBegin; 481 PetscCheck(!A->was_assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot call on assembled matrix."); 482 PetscCheck(m * n + a->nz <= a->maxnz, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of entries in matrix will be larger than maximum nonzeros allocated for %" PetscInt_FMT " in MatSeqAIJSetTotalPreallocation()", a->maxnz); 483 484 PetscCall(MatSeqAIJGetArray(A, &aa)); 485 for (k = 0; k < m; k++) { /* loop over added rows */ 486 row = im[k]; 487 rp = aj + ai[row]; 488 ap = aa + ai[row]; 489 490 PetscCall(PetscMemcpy(rp, in, n * sizeof(PetscInt))); 491 if (!A->structure_only) { 492 if (v) { 493 PetscCall(PetscMemcpy(ap, v, n * sizeof(PetscScalar))); 494 v += n; 495 } else { 496 PetscCall(PetscMemzero(ap, n * sizeof(PetscScalar))); 497 } 498 } 499 a->ilen[row] = n; 500 a->imax[row] = n; 501 a->i[row + 1] = a->i[row] + n; 502 a->nz += n; 503 } 504 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 505 PetscFunctionReturn(PETSC_SUCCESS); 506 } 507 508 /*@ 509 MatSeqAIJSetTotalPreallocation - Sets an upper bound on the total number of expected nonzeros in the matrix. 510 511 Input Parameters: 512 + A - the `MATSEQAIJ` matrix 513 - nztotal - bound on the number of nonzeros 514 515 Level: advanced 516 517 Notes: 518 This can be called if you will be provided the matrix row by row (from row zero) with sorted column indices for each row. 519 Simply call `MatSetValues()` after this call to provide the matrix entries in the usual manner. This matrix may be used 520 as always with multiple matrix assemblies. 521 522 .seealso: `MatSetOption()`, `MAT_SORTED_FULL`, `MatSetValues()`, `MatSeqAIJSetPreallocation()` 523 @*/ 524 525 PetscErrorCode MatSeqAIJSetTotalPreallocation(Mat A, PetscInt nztotal) 526 { 527 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 528 529 PetscFunctionBegin; 530 PetscCall(PetscLayoutSetUp(A->rmap)); 531 PetscCall(PetscLayoutSetUp(A->cmap)); 532 a->maxnz = nztotal; 533 if (!a->imax) { PetscCall(PetscMalloc1(A->rmap->n, &a->imax)); } 534 if (!a->ilen) { 535 PetscCall(PetscMalloc1(A->rmap->n, &a->ilen)); 536 } else { 537 PetscCall(PetscMemzero(a->ilen, A->rmap->n * sizeof(PetscInt))); 538 } 539 540 /* allocate the matrix space */ 541 if (A->structure_only) { 542 PetscCall(PetscMalloc1(nztotal, &a->j)); 543 PetscCall(PetscMalloc1(A->rmap->n + 1, &a->i)); 544 } else { 545 PetscCall(PetscMalloc3(nztotal, &a->a, nztotal, &a->j, A->rmap->n + 1, &a->i)); 546 } 547 a->i[0] = 0; 548 if (A->structure_only) { 549 a->singlemalloc = PETSC_FALSE; 550 a->free_a = PETSC_FALSE; 551 } else { 552 a->singlemalloc = PETSC_TRUE; 553 a->free_a = PETSC_TRUE; 554 } 555 a->free_ij = PETSC_TRUE; 556 A->ops->setvalues = MatSetValues_SeqAIJ_SortedFullNoPreallocation; 557 A->preallocated = PETSC_TRUE; 558 PetscFunctionReturn(PETSC_SUCCESS); 559 } 560 561 PetscErrorCode MatSetValues_SeqAIJ_SortedFull(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is) 562 { 563 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 564 PetscInt *rp, k, row; 565 PetscInt *ai = a->i, *ailen = a->ilen; 566 PetscInt *aj = a->j; 567 MatScalar *aa, *ap; 568 569 PetscFunctionBegin; 570 PetscCall(MatSeqAIJGetArray(A, &aa)); 571 for (k = 0; k < m; k++) { /* loop over added rows */ 572 row = im[k]; 573 PetscCheck(n <= a->imax[row], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Preallocation for row %" PetscInt_FMT " does not match number of columns provided", n); 574 rp = aj + ai[row]; 575 ap = aa + ai[row]; 576 if (!A->was_assembled) PetscCall(PetscMemcpy(rp, in, n * sizeof(PetscInt))); 577 if (!A->structure_only) { 578 if (v) { 579 PetscCall(PetscMemcpy(ap, v, n * sizeof(PetscScalar))); 580 v += n; 581 } else { 582 PetscCall(PetscMemzero(ap, n * sizeof(PetscScalar))); 583 } 584 } 585 ailen[row] = n; 586 a->nz += n; 587 } 588 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 589 PetscFunctionReturn(PETSC_SUCCESS); 590 } 591 592 PetscErrorCode MatGetValues_SeqAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], PetscScalar v[]) 593 { 594 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 595 PetscInt *rp, k, low, high, t, row, nrow, i, col, l, *aj = a->j; 596 PetscInt *ai = a->i, *ailen = a->ilen; 597 const MatScalar *ap, *aa; 598 599 PetscFunctionBegin; 600 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 601 for (k = 0; k < m; k++) { /* loop over rows */ 602 row = im[k]; 603 if (row < 0) { 604 v += n; 605 continue; 606 } /* negative row */ 607 PetscCheck(row < A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, row, A->rmap->n - 1); 608 rp = aj + ai[row]; 609 ap = aa + ai[row]; 610 nrow = ailen[row]; 611 for (l = 0; l < n; l++) { /* loop over columns */ 612 if (in[l] < 0) { 613 v++; 614 continue; 615 } /* negative column */ 616 PetscCheck(in[l] < A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[l], A->cmap->n - 1); 617 col = in[l]; 618 high = nrow; 619 low = 0; /* assume unsorted */ 620 while (high - low > 5) { 621 t = (low + high) / 2; 622 if (rp[t] > col) high = t; 623 else low = t; 624 } 625 for (i = low; i < high; i++) { 626 if (rp[i] > col) break; 627 if (rp[i] == col) { 628 *v++ = ap[i]; 629 goto finished; 630 } 631 } 632 *v++ = 0.0; 633 finished:; 634 } 635 } 636 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 637 PetscFunctionReturn(PETSC_SUCCESS); 638 } 639 640 PetscErrorCode MatView_SeqAIJ_Binary(Mat mat, PetscViewer viewer) 641 { 642 Mat_SeqAIJ *A = (Mat_SeqAIJ *)mat->data; 643 const PetscScalar *av; 644 PetscInt header[4], M, N, m, nz, i; 645 PetscInt *rowlens; 646 647 PetscFunctionBegin; 648 PetscCall(PetscViewerSetUp(viewer)); 649 650 M = mat->rmap->N; 651 N = mat->cmap->N; 652 m = mat->rmap->n; 653 nz = A->nz; 654 655 /* write matrix header */ 656 header[0] = MAT_FILE_CLASSID; 657 header[1] = M; 658 header[2] = N; 659 header[3] = nz; 660 PetscCall(PetscViewerBinaryWrite(viewer, header, 4, PETSC_INT)); 661 662 /* fill in and store row lengths */ 663 PetscCall(PetscMalloc1(m, &rowlens)); 664 for (i = 0; i < m; i++) rowlens[i] = A->i[i + 1] - A->i[i]; 665 PetscCall(PetscViewerBinaryWrite(viewer, rowlens, m, PETSC_INT)); 666 PetscCall(PetscFree(rowlens)); 667 /* store column indices */ 668 PetscCall(PetscViewerBinaryWrite(viewer, A->j, nz, PETSC_INT)); 669 /* store nonzero values */ 670 PetscCall(MatSeqAIJGetArrayRead(mat, &av)); 671 PetscCall(PetscViewerBinaryWrite(viewer, av, nz, PETSC_SCALAR)); 672 PetscCall(MatSeqAIJRestoreArrayRead(mat, &av)); 673 674 /* write block size option to the viewer's .info file */ 675 PetscCall(MatView_Binary_BlockSizes(mat, viewer)); 676 PetscFunctionReturn(PETSC_SUCCESS); 677 } 678 679 static PetscErrorCode MatView_SeqAIJ_ASCII_structonly(Mat A, PetscViewer viewer) 680 { 681 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 682 PetscInt i, k, m = A->rmap->N; 683 684 PetscFunctionBegin; 685 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 686 for (i = 0; i < m; i++) { 687 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 688 for (k = a->i[i]; k < a->i[i + 1]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ") ", a->j[k])); 689 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 690 } 691 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 692 PetscFunctionReturn(PETSC_SUCCESS); 693 } 694 695 extern PetscErrorCode MatSeqAIJFactorInfo_Matlab(Mat, PetscViewer); 696 697 PetscErrorCode MatView_SeqAIJ_ASCII(Mat A, PetscViewer viewer) 698 { 699 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 700 const PetscScalar *av; 701 PetscInt i, j, m = A->rmap->n; 702 const char *name; 703 PetscViewerFormat format; 704 705 PetscFunctionBegin; 706 if (A->structure_only) { 707 PetscCall(MatView_SeqAIJ_ASCII_structonly(A, viewer)); 708 PetscFunctionReturn(PETSC_SUCCESS); 709 } 710 711 PetscCall(PetscViewerGetFormat(viewer, &format)); 712 if (format == PETSC_VIEWER_ASCII_FACTOR_INFO || format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(PETSC_SUCCESS); 713 714 /* trigger copy to CPU if needed */ 715 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 716 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 717 if (format == PETSC_VIEWER_ASCII_MATLAB) { 718 PetscInt nofinalvalue = 0; 719 if (m && ((a->i[m] == a->i[m - 1]) || (a->j[a->nz - 1] != A->cmap->n - 1))) { 720 /* Need a dummy value to ensure the dimension of the matrix. */ 721 nofinalvalue = 1; 722 } 723 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 724 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Size = %" PetscInt_FMT " %" PetscInt_FMT " \n", m, A->cmap->n)); 725 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Nonzeros = %" PetscInt_FMT " \n", a->nz)); 726 #if defined(PETSC_USE_COMPLEX) 727 PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = zeros(%" PetscInt_FMT ",4);\n", a->nz + nofinalvalue)); 728 #else 729 PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = zeros(%" PetscInt_FMT ",3);\n", a->nz + nofinalvalue)); 730 #endif 731 PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = [\n")); 732 733 for (i = 0; i < m; i++) { 734 for (j = a->i[i]; j < a->i[i + 1]; j++) { 735 #if defined(PETSC_USE_COMPLEX) 736 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e %18.16e\n", i + 1, a->j[j] + 1, (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 737 #else 738 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n", i + 1, a->j[j] + 1, (double)a->a[j])); 739 #endif 740 } 741 } 742 if (nofinalvalue) { 743 #if defined(PETSC_USE_COMPLEX) 744 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e %18.16e\n", m, A->cmap->n, 0., 0.)); 745 #else 746 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n", m, A->cmap->n, 0.0)); 747 #endif 748 } 749 PetscCall(PetscObjectGetName((PetscObject)A, &name)); 750 PetscCall(PetscViewerASCIIPrintf(viewer, "];\n %s = spconvert(zzz);\n", name)); 751 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 752 } else if (format == PETSC_VIEWER_ASCII_COMMON) { 753 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 754 for (i = 0; i < m; i++) { 755 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 756 for (j = a->i[i]; j < a->i[i + 1]; j++) { 757 #if defined(PETSC_USE_COMPLEX) 758 if (PetscImaginaryPart(a->a[j]) > 0.0 && PetscRealPart(a->a[j]) != 0.0) { 759 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 760 } else if (PetscImaginaryPart(a->a[j]) < 0.0 && PetscRealPart(a->a[j]) != 0.0) { 761 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)-PetscImaginaryPart(a->a[j]))); 762 } else if (PetscRealPart(a->a[j]) != 0.0) { 763 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 764 } 765 #else 766 if (a->a[j] != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 767 #endif 768 } 769 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 770 } 771 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 772 } else if (format == PETSC_VIEWER_ASCII_SYMMODU) { 773 PetscInt nzd = 0, fshift = 1, *sptr; 774 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 775 PetscCall(PetscMalloc1(m + 1, &sptr)); 776 for (i = 0; i < m; i++) { 777 sptr[i] = nzd + 1; 778 for (j = a->i[i]; j < a->i[i + 1]; j++) { 779 if (a->j[j] >= i) { 780 #if defined(PETSC_USE_COMPLEX) 781 if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) nzd++; 782 #else 783 if (a->a[j] != 0.0) nzd++; 784 #endif 785 } 786 } 787 } 788 sptr[m] = nzd + 1; 789 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT "\n\n", m, nzd)); 790 for (i = 0; i < m + 1; i += 6) { 791 if (i + 4 < m) { 792 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3], sptr[i + 4], sptr[i + 5])); 793 } else if (i + 3 < m) { 794 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3], sptr[i + 4])); 795 } else if (i + 2 < m) { 796 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3])); 797 } else if (i + 1 < m) { 798 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2])); 799 } else if (i < m) { 800 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1])); 801 } else { 802 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "\n", sptr[i])); 803 } 804 } 805 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 806 PetscCall(PetscFree(sptr)); 807 for (i = 0; i < m; i++) { 808 for (j = a->i[i]; j < a->i[i + 1]; j++) { 809 if (a->j[j] >= i) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " ", a->j[j] + fshift)); 810 } 811 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 812 } 813 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 814 for (i = 0; i < m; i++) { 815 for (j = a->i[i]; j < a->i[i + 1]; j++) { 816 if (a->j[j] >= i) { 817 #if defined(PETSC_USE_COMPLEX) 818 if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " %18.16e %18.16e ", (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 819 #else 820 if (a->a[j] != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " %18.16e ", (double)a->a[j])); 821 #endif 822 } 823 } 824 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 825 } 826 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 827 } else if (format == PETSC_VIEWER_ASCII_DENSE) { 828 PetscInt cnt = 0, jcnt; 829 PetscScalar value; 830 #if defined(PETSC_USE_COMPLEX) 831 PetscBool realonly = PETSC_TRUE; 832 833 for (i = 0; i < a->i[m]; i++) { 834 if (PetscImaginaryPart(a->a[i]) != 0.0) { 835 realonly = PETSC_FALSE; 836 break; 837 } 838 } 839 #endif 840 841 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 842 for (i = 0; i < m; i++) { 843 jcnt = 0; 844 for (j = 0; j < A->cmap->n; j++) { 845 if (jcnt < a->i[i + 1] - a->i[i] && j == a->j[cnt]) { 846 value = a->a[cnt++]; 847 jcnt++; 848 } else { 849 value = 0.0; 850 } 851 #if defined(PETSC_USE_COMPLEX) 852 if (realonly) { 853 PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e ", (double)PetscRealPart(value))); 854 } else { 855 PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e+%7.5e i ", (double)PetscRealPart(value), (double)PetscImaginaryPart(value))); 856 } 857 #else 858 PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e ", (double)value)); 859 #endif 860 } 861 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 862 } 863 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 864 } else if (format == PETSC_VIEWER_ASCII_MATRIXMARKET) { 865 PetscInt fshift = 1; 866 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 867 #if defined(PETSC_USE_COMPLEX) 868 PetscCall(PetscViewerASCIIPrintf(viewer, "%%%%MatrixMarket matrix coordinate complex general\n")); 869 #else 870 PetscCall(PetscViewerASCIIPrintf(viewer, "%%%%MatrixMarket matrix coordinate real general\n")); 871 #endif 872 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", m, A->cmap->n, a->nz)); 873 for (i = 0; i < m; i++) { 874 for (j = a->i[i]; j < a->i[i + 1]; j++) { 875 #if defined(PETSC_USE_COMPLEX) 876 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %g %g\n", i + fshift, a->j[j] + fshift, (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 877 #else 878 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %g\n", i + fshift, a->j[j] + fshift, (double)a->a[j])); 879 #endif 880 } 881 } 882 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 883 } else { 884 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 885 if (A->factortype) { 886 for (i = 0; i < m; i++) { 887 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 888 /* L part */ 889 for (j = a->i[i]; j < a->i[i + 1]; j++) { 890 #if defined(PETSC_USE_COMPLEX) 891 if (PetscImaginaryPart(a->a[j]) > 0.0) { 892 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 893 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 894 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)(-PetscImaginaryPart(a->a[j])))); 895 } else { 896 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 897 } 898 #else 899 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 900 #endif 901 } 902 /* diagonal */ 903 j = a->diag[i]; 904 #if defined(PETSC_USE_COMPLEX) 905 if (PetscImaginaryPart(a->a[j]) > 0.0) { 906 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(1.0 / a->a[j]), (double)PetscImaginaryPart(1.0 / a->a[j]))); 907 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 908 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(1.0 / a->a[j]), (double)(-PetscImaginaryPart(1.0 / a->a[j])))); 909 } else { 910 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(1.0 / a->a[j]))); 911 } 912 #else 913 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)(1.0 / a->a[j]))); 914 #endif 915 916 /* U part */ 917 for (j = a->diag[i + 1] + 1; j < a->diag[i]; j++) { 918 #if defined(PETSC_USE_COMPLEX) 919 if (PetscImaginaryPart(a->a[j]) > 0.0) { 920 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 921 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 922 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)(-PetscImaginaryPart(a->a[j])))); 923 } else { 924 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 925 } 926 #else 927 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 928 #endif 929 } 930 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 931 } 932 } else { 933 for (i = 0; i < m; i++) { 934 PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i)); 935 for (j = a->i[i]; j < a->i[i + 1]; j++) { 936 #if defined(PETSC_USE_COMPLEX) 937 if (PetscImaginaryPart(a->a[j]) > 0.0) { 938 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j]))); 939 } else if (PetscImaginaryPart(a->a[j]) < 0.0) { 940 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)-PetscImaginaryPart(a->a[j]))); 941 } else { 942 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j]))); 943 } 944 #else 945 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j])); 946 #endif 947 } 948 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 949 } 950 } 951 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 952 } 953 PetscCall(PetscViewerFlush(viewer)); 954 PetscFunctionReturn(PETSC_SUCCESS); 955 } 956 957 #include <petscdraw.h> 958 PetscErrorCode MatView_SeqAIJ_Draw_Zoom(PetscDraw draw, void *Aa) 959 { 960 Mat A = (Mat)Aa; 961 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 962 PetscInt i, j, m = A->rmap->n; 963 int color; 964 PetscReal xl, yl, xr, yr, x_l, x_r, y_l, y_r; 965 PetscViewer viewer; 966 PetscViewerFormat format; 967 const PetscScalar *aa; 968 969 PetscFunctionBegin; 970 PetscCall(PetscObjectQuery((PetscObject)A, "Zoomviewer", (PetscObject *)&viewer)); 971 PetscCall(PetscViewerGetFormat(viewer, &format)); 972 PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr)); 973 974 /* loop over matrix elements drawing boxes */ 975 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 976 if (format != PETSC_VIEWER_DRAW_CONTOUR) { 977 PetscDrawCollectiveBegin(draw); 978 /* Blue for negative, Cyan for zero and Red for positive */ 979 color = PETSC_DRAW_BLUE; 980 for (i = 0; i < m; i++) { 981 y_l = m - i - 1.0; 982 y_r = y_l + 1.0; 983 for (j = a->i[i]; j < a->i[i + 1]; j++) { 984 x_l = a->j[j]; 985 x_r = x_l + 1.0; 986 if (PetscRealPart(aa[j]) >= 0.) continue; 987 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 988 } 989 } 990 color = PETSC_DRAW_CYAN; 991 for (i = 0; i < m; i++) { 992 y_l = m - i - 1.0; 993 y_r = y_l + 1.0; 994 for (j = a->i[i]; j < a->i[i + 1]; j++) { 995 x_l = a->j[j]; 996 x_r = x_l + 1.0; 997 if (aa[j] != 0.) continue; 998 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 999 } 1000 } 1001 color = PETSC_DRAW_RED; 1002 for (i = 0; i < m; i++) { 1003 y_l = m - i - 1.0; 1004 y_r = y_l + 1.0; 1005 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1006 x_l = a->j[j]; 1007 x_r = x_l + 1.0; 1008 if (PetscRealPart(aa[j]) <= 0.) continue; 1009 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 1010 } 1011 } 1012 PetscDrawCollectiveEnd(draw); 1013 } else { 1014 /* use contour shading to indicate magnitude of values */ 1015 /* first determine max of all nonzero values */ 1016 PetscReal minv = 0.0, maxv = 0.0; 1017 PetscInt nz = a->nz, count = 0; 1018 PetscDraw popup; 1019 1020 for (i = 0; i < nz; i++) { 1021 if (PetscAbsScalar(aa[i]) > maxv) maxv = PetscAbsScalar(aa[i]); 1022 } 1023 if (minv >= maxv) maxv = minv + PETSC_SMALL; 1024 PetscCall(PetscDrawGetPopup(draw, &popup)); 1025 PetscCall(PetscDrawScalePopup(popup, minv, maxv)); 1026 1027 PetscDrawCollectiveBegin(draw); 1028 for (i = 0; i < m; i++) { 1029 y_l = m - i - 1.0; 1030 y_r = y_l + 1.0; 1031 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1032 x_l = a->j[j]; 1033 x_r = x_l + 1.0; 1034 color = PetscDrawRealToColor(PetscAbsScalar(aa[count]), minv, maxv); 1035 PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color)); 1036 count++; 1037 } 1038 } 1039 PetscDrawCollectiveEnd(draw); 1040 } 1041 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1042 PetscFunctionReturn(PETSC_SUCCESS); 1043 } 1044 1045 #include <petscdraw.h> 1046 PetscErrorCode MatView_SeqAIJ_Draw(Mat A, PetscViewer viewer) 1047 { 1048 PetscDraw draw; 1049 PetscReal xr, yr, xl, yl, h, w; 1050 PetscBool isnull; 1051 1052 PetscFunctionBegin; 1053 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1054 PetscCall(PetscDrawIsNull(draw, &isnull)); 1055 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1056 1057 xr = A->cmap->n; 1058 yr = A->rmap->n; 1059 h = yr / 10.0; 1060 w = xr / 10.0; 1061 xr += w; 1062 yr += h; 1063 xl = -w; 1064 yl = -h; 1065 PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr)); 1066 PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", (PetscObject)viewer)); 1067 PetscCall(PetscDrawZoom(draw, MatView_SeqAIJ_Draw_Zoom, A)); 1068 PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", NULL)); 1069 PetscCall(PetscDrawSave(draw)); 1070 PetscFunctionReturn(PETSC_SUCCESS); 1071 } 1072 1073 PetscErrorCode MatView_SeqAIJ(Mat A, PetscViewer viewer) 1074 { 1075 PetscBool iascii, isbinary, isdraw; 1076 1077 PetscFunctionBegin; 1078 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1079 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 1080 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1081 if (iascii) PetscCall(MatView_SeqAIJ_ASCII(A, viewer)); 1082 else if (isbinary) PetscCall(MatView_SeqAIJ_Binary(A, viewer)); 1083 else if (isdraw) PetscCall(MatView_SeqAIJ_Draw(A, viewer)); 1084 PetscCall(MatView_SeqAIJ_Inode(A, viewer)); 1085 PetscFunctionReturn(PETSC_SUCCESS); 1086 } 1087 1088 PetscErrorCode MatAssemblyEnd_SeqAIJ(Mat A, MatAssemblyType mode) 1089 { 1090 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1091 PetscInt fshift = 0, i, *ai = a->i, *aj = a->j, *imax = a->imax; 1092 PetscInt m = A->rmap->n, *ip, N, *ailen = a->ilen, rmax = 0; 1093 MatScalar *aa = a->a, *ap; 1094 PetscReal ratio = 0.6; 1095 1096 PetscFunctionBegin; 1097 if (mode == MAT_FLUSH_ASSEMBLY) PetscFunctionReturn(PETSC_SUCCESS); 1098 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1099 if (A->was_assembled && A->ass_nonzerostate == A->nonzerostate) { 1100 /* we need to respect users asking to use or not the inodes routine in between matrix assemblies */ 1101 PetscCall(MatAssemblyEnd_SeqAIJ_Inode(A, mode)); 1102 PetscFunctionReturn(PETSC_SUCCESS); 1103 } 1104 1105 if (m) rmax = ailen[0]; /* determine row with most nonzeros */ 1106 for (i = 1; i < m; i++) { 1107 /* move each row back by the amount of empty slots (fshift) before it*/ 1108 fshift += imax[i - 1] - ailen[i - 1]; 1109 rmax = PetscMax(rmax, ailen[i]); 1110 if (fshift) { 1111 ip = aj + ai[i]; 1112 ap = aa + ai[i]; 1113 N = ailen[i]; 1114 PetscCall(PetscArraymove(ip - fshift, ip, N)); 1115 if (!A->structure_only) PetscCall(PetscArraymove(ap - fshift, ap, N)); 1116 } 1117 ai[i] = ai[i - 1] + ailen[i - 1]; 1118 } 1119 if (m) { 1120 fshift += imax[m - 1] - ailen[m - 1]; 1121 ai[m] = ai[m - 1] + ailen[m - 1]; 1122 } 1123 /* reset ilen and imax for each row */ 1124 a->nonzerorowcnt = 0; 1125 if (A->structure_only) { 1126 PetscCall(PetscFree(a->imax)); 1127 PetscCall(PetscFree(a->ilen)); 1128 } else { /* !A->structure_only */ 1129 for (i = 0; i < m; i++) { 1130 ailen[i] = imax[i] = ai[i + 1] - ai[i]; 1131 a->nonzerorowcnt += ((ai[i + 1] - ai[i]) > 0); 1132 } 1133 } 1134 a->nz = ai[m]; 1135 PetscCheck(!fshift || a->nounused != -1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unused space detected in matrix: %" PetscInt_FMT " X %" PetscInt_FMT ", %" PetscInt_FMT " unneeded", m, A->cmap->n, fshift); 1136 1137 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 1138 PetscCall(PetscInfo(A, "Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT "; storage space: %" PetscInt_FMT " unneeded,%" PetscInt_FMT " used\n", m, A->cmap->n, fshift, a->nz)); 1139 PetscCall(PetscInfo(A, "Number of mallocs during MatSetValues() is %" PetscInt_FMT "\n", a->reallocs)); 1140 PetscCall(PetscInfo(A, "Maximum nonzeros in any row is %" PetscInt_FMT "\n", rmax)); 1141 1142 A->info.mallocs += a->reallocs; 1143 a->reallocs = 0; 1144 A->info.nz_unneeded = (PetscReal)fshift; 1145 a->rmax = rmax; 1146 1147 if (!A->structure_only) PetscCall(MatCheckCompressedRow(A, a->nonzerorowcnt, &a->compressedrow, a->i, m, ratio)); 1148 PetscCall(MatAssemblyEnd_SeqAIJ_Inode(A, mode)); 1149 PetscFunctionReturn(PETSC_SUCCESS); 1150 } 1151 1152 PetscErrorCode MatRealPart_SeqAIJ(Mat A) 1153 { 1154 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1155 PetscInt i, nz = a->nz; 1156 MatScalar *aa; 1157 1158 PetscFunctionBegin; 1159 PetscCall(MatSeqAIJGetArray(A, &aa)); 1160 for (i = 0; i < nz; i++) aa[i] = PetscRealPart(aa[i]); 1161 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 1162 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1163 PetscFunctionReturn(PETSC_SUCCESS); 1164 } 1165 1166 PetscErrorCode MatImaginaryPart_SeqAIJ(Mat A) 1167 { 1168 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1169 PetscInt i, nz = a->nz; 1170 MatScalar *aa; 1171 1172 PetscFunctionBegin; 1173 PetscCall(MatSeqAIJGetArray(A, &aa)); 1174 for (i = 0; i < nz; i++) aa[i] = PetscImaginaryPart(aa[i]); 1175 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 1176 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1177 PetscFunctionReturn(PETSC_SUCCESS); 1178 } 1179 1180 PetscErrorCode MatZeroEntries_SeqAIJ(Mat A) 1181 { 1182 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1183 MatScalar *aa; 1184 1185 PetscFunctionBegin; 1186 PetscCall(MatSeqAIJGetArrayWrite(A, &aa)); 1187 PetscCall(PetscArrayzero(aa, a->i[A->rmap->n])); 1188 PetscCall(MatSeqAIJRestoreArrayWrite(A, &aa)); 1189 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 1190 PetscFunctionReturn(PETSC_SUCCESS); 1191 } 1192 1193 PETSC_INTERN PetscErrorCode MatResetPreallocationCOO_SeqAIJ(Mat A) 1194 { 1195 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1196 1197 PetscFunctionBegin; 1198 PetscCall(PetscFree(a->perm)); 1199 PetscCall(PetscFree(a->jmap)); 1200 PetscFunctionReturn(PETSC_SUCCESS); 1201 } 1202 1203 PetscErrorCode MatDestroy_SeqAIJ(Mat A) 1204 { 1205 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1206 1207 PetscFunctionBegin; 1208 #if defined(PETSC_USE_LOG) 1209 PetscCall(PetscLogObjectState((PetscObject)A, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT ", NZ=%" PetscInt_FMT, A->rmap->n, A->cmap->n, a->nz)); 1210 #endif 1211 PetscCall(MatSeqXAIJFreeAIJ(A, &a->a, &a->j, &a->i)); 1212 PetscCall(MatResetPreallocationCOO_SeqAIJ(A)); 1213 PetscCall(ISDestroy(&a->row)); 1214 PetscCall(ISDestroy(&a->col)); 1215 PetscCall(PetscFree(a->diag)); 1216 PetscCall(PetscFree(a->ibdiag)); 1217 PetscCall(PetscFree(a->imax)); 1218 PetscCall(PetscFree(a->ilen)); 1219 PetscCall(PetscFree(a->ipre)); 1220 PetscCall(PetscFree3(a->idiag, a->mdiag, a->ssor_work)); 1221 PetscCall(PetscFree(a->solve_work)); 1222 PetscCall(ISDestroy(&a->icol)); 1223 PetscCall(PetscFree(a->saved_values)); 1224 PetscCall(PetscFree2(a->compressedrow.i, a->compressedrow.rindex)); 1225 PetscCall(MatDestroy_SeqAIJ_Inode(A)); 1226 PetscCall(PetscFree(A->data)); 1227 1228 /* MatMatMultNumeric_SeqAIJ_SeqAIJ_Sorted may allocate this. 1229 That function is so heavily used (sometimes in an hidden way through multnumeric function pointers) 1230 that is hard to properly add this data to the MatProduct data. We free it here to avoid 1231 users reusing the matrix object with different data to incur in obscure segmentation faults 1232 due to different matrix sizes */ 1233 PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc__ab_dense", NULL)); 1234 1235 PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL)); 1236 PetscCall(PetscObjectComposeFunction((PetscObject)A, "PetscMatlabEnginePut_C", NULL)); 1237 PetscCall(PetscObjectComposeFunction((PetscObject)A, "PetscMatlabEngineGet_C", NULL)); 1238 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetColumnIndices_C", NULL)); 1239 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatStoreValues_C", NULL)); 1240 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatRetrieveValues_C", NULL)); 1241 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqsbaij_C", NULL)); 1242 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqbaij_C", NULL)); 1243 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijperm_C", NULL)); 1244 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijsell_C", NULL)); 1245 #if defined(PETSC_HAVE_MKL_SPARSE) 1246 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijmkl_C", NULL)); 1247 #endif 1248 #if defined(PETSC_HAVE_CUDA) 1249 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijcusparse_C", NULL)); 1250 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", NULL)); 1251 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", NULL)); 1252 #endif 1253 #if defined(PETSC_HAVE_HIP) 1254 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijhipsparse_C", NULL)); 1255 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", NULL)); 1256 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", NULL)); 1257 #endif 1258 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 1259 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijkokkos_C", NULL)); 1260 #endif 1261 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijcrl_C", NULL)); 1262 #if defined(PETSC_HAVE_ELEMENTAL) 1263 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_elemental_C", NULL)); 1264 #endif 1265 #if defined(PETSC_HAVE_SCALAPACK) 1266 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_scalapack_C", NULL)); 1267 #endif 1268 #if defined(PETSC_HAVE_HYPRE) 1269 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_hypre_C", NULL)); 1270 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", NULL)); 1271 #endif 1272 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqdense_C", NULL)); 1273 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqsell_C", NULL)); 1274 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_is_C", NULL)); 1275 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatIsTranspose_C", NULL)); 1276 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatIsHermitianTranspose_C", NULL)); 1277 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetPreallocation_C", NULL)); 1278 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatResetPreallocation_C", NULL)); 1279 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetPreallocationCSR_C", NULL)); 1280 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatReorderForNonzeroDiagonal_C", NULL)); 1281 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_is_seqaij_C", NULL)); 1282 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqdense_seqaij_C", NULL)); 1283 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaij_C", NULL)); 1284 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJKron_C", NULL)); 1285 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL)); 1286 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL)); 1287 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatFactorGetSolverType_C", NULL)); 1288 /* these calls do not belong here: the subclasses Duplicate/Destroy are wrong */ 1289 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaijsell_seqaij_C", NULL)); 1290 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaijperm_seqaij_C", NULL)); 1291 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijviennacl_C", NULL)); 1292 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijviennacl_seqdense_C", NULL)); 1293 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijviennacl_seqaij_C", NULL)); 1294 PetscFunctionReturn(PETSC_SUCCESS); 1295 } 1296 1297 PetscErrorCode MatSetOption_SeqAIJ(Mat A, MatOption op, PetscBool flg) 1298 { 1299 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1300 1301 PetscFunctionBegin; 1302 switch (op) { 1303 case MAT_ROW_ORIENTED: 1304 a->roworiented = flg; 1305 break; 1306 case MAT_KEEP_NONZERO_PATTERN: 1307 a->keepnonzeropattern = flg; 1308 break; 1309 case MAT_NEW_NONZERO_LOCATIONS: 1310 a->nonew = (flg ? 0 : 1); 1311 break; 1312 case MAT_NEW_NONZERO_LOCATION_ERR: 1313 a->nonew = (flg ? -1 : 0); 1314 break; 1315 case MAT_NEW_NONZERO_ALLOCATION_ERR: 1316 a->nonew = (flg ? -2 : 0); 1317 break; 1318 case MAT_UNUSED_NONZERO_LOCATION_ERR: 1319 a->nounused = (flg ? -1 : 0); 1320 break; 1321 case MAT_IGNORE_ZERO_ENTRIES: 1322 a->ignorezeroentries = flg; 1323 break; 1324 case MAT_SPD: 1325 case MAT_SYMMETRIC: 1326 case MAT_STRUCTURALLY_SYMMETRIC: 1327 case MAT_HERMITIAN: 1328 case MAT_SYMMETRY_ETERNAL: 1329 case MAT_STRUCTURE_ONLY: 1330 case MAT_STRUCTURAL_SYMMETRY_ETERNAL: 1331 case MAT_SPD_ETERNAL: 1332 /* if the diagonal matrix is square it inherits some of the properties above */ 1333 break; 1334 case MAT_FORCE_DIAGONAL_ENTRIES: 1335 case MAT_IGNORE_OFF_PROC_ENTRIES: 1336 case MAT_USE_HASH_TABLE: 1337 PetscCall(PetscInfo(A, "Option %s ignored\n", MatOptions[op])); 1338 break; 1339 case MAT_USE_INODES: 1340 PetscCall(MatSetOption_SeqAIJ_Inode(A, MAT_USE_INODES, flg)); 1341 break; 1342 case MAT_SUBMAT_SINGLEIS: 1343 A->submat_singleis = flg; 1344 break; 1345 case MAT_SORTED_FULL: 1346 if (flg) A->ops->setvalues = MatSetValues_SeqAIJ_SortedFull; 1347 else A->ops->setvalues = MatSetValues_SeqAIJ; 1348 break; 1349 case MAT_FORM_EXPLICIT_TRANSPOSE: 1350 A->form_explicit_transpose = flg; 1351 break; 1352 default: 1353 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "unknown option %d", op); 1354 } 1355 PetscFunctionReturn(PETSC_SUCCESS); 1356 } 1357 1358 PetscErrorCode MatGetDiagonal_SeqAIJ(Mat A, Vec v) 1359 { 1360 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1361 PetscInt i, j, n, *ai = a->i, *aj = a->j; 1362 PetscScalar *x; 1363 const PetscScalar *aa; 1364 1365 PetscFunctionBegin; 1366 PetscCall(VecGetLocalSize(v, &n)); 1367 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 1368 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 1369 if (A->factortype == MAT_FACTOR_ILU || A->factortype == MAT_FACTOR_LU) { 1370 PetscInt *diag = a->diag; 1371 PetscCall(VecGetArrayWrite(v, &x)); 1372 for (i = 0; i < n; i++) x[i] = 1.0 / aa[diag[i]]; 1373 PetscCall(VecRestoreArrayWrite(v, &x)); 1374 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1375 PetscFunctionReturn(PETSC_SUCCESS); 1376 } 1377 1378 PetscCall(VecGetArrayWrite(v, &x)); 1379 for (i = 0; i < n; i++) { 1380 x[i] = 0.0; 1381 for (j = ai[i]; j < ai[i + 1]; j++) { 1382 if (aj[j] == i) { 1383 x[i] = aa[j]; 1384 break; 1385 } 1386 } 1387 } 1388 PetscCall(VecRestoreArrayWrite(v, &x)); 1389 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1390 PetscFunctionReturn(PETSC_SUCCESS); 1391 } 1392 1393 #include <../src/mat/impls/aij/seq/ftn-kernels/fmult.h> 1394 PetscErrorCode MatMultTransposeAdd_SeqAIJ(Mat A, Vec xx, Vec zz, Vec yy) 1395 { 1396 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1397 const MatScalar *aa; 1398 PetscScalar *y; 1399 const PetscScalar *x; 1400 PetscInt m = A->rmap->n; 1401 #if !defined(PETSC_USE_FORTRAN_KERNEL_MULTTRANSPOSEAIJ) 1402 const MatScalar *v; 1403 PetscScalar alpha; 1404 PetscInt n, i, j; 1405 const PetscInt *idx, *ii, *ridx = NULL; 1406 Mat_CompressedRow cprow = a->compressedrow; 1407 PetscBool usecprow = cprow.use; 1408 #endif 1409 1410 PetscFunctionBegin; 1411 if (zz != yy) PetscCall(VecCopy(zz, yy)); 1412 PetscCall(VecGetArrayRead(xx, &x)); 1413 PetscCall(VecGetArray(yy, &y)); 1414 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 1415 1416 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTTRANSPOSEAIJ) 1417 fortranmulttransposeaddaij_(&m, x, a->i, a->j, aa, y); 1418 #else 1419 if (usecprow) { 1420 m = cprow.nrows; 1421 ii = cprow.i; 1422 ridx = cprow.rindex; 1423 } else { 1424 ii = a->i; 1425 } 1426 for (i = 0; i < m; i++) { 1427 idx = a->j + ii[i]; 1428 v = aa + ii[i]; 1429 n = ii[i + 1] - ii[i]; 1430 if (usecprow) { 1431 alpha = x[ridx[i]]; 1432 } else { 1433 alpha = x[i]; 1434 } 1435 for (j = 0; j < n; j++) y[idx[j]] += alpha * v[j]; 1436 } 1437 #endif 1438 PetscCall(PetscLogFlops(2.0 * a->nz)); 1439 PetscCall(VecRestoreArrayRead(xx, &x)); 1440 PetscCall(VecRestoreArray(yy, &y)); 1441 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1442 PetscFunctionReturn(PETSC_SUCCESS); 1443 } 1444 1445 PetscErrorCode MatMultTranspose_SeqAIJ(Mat A, Vec xx, Vec yy) 1446 { 1447 PetscFunctionBegin; 1448 PetscCall(VecSet(yy, 0.0)); 1449 PetscCall(MatMultTransposeAdd_SeqAIJ(A, xx, yy, yy)); 1450 PetscFunctionReturn(PETSC_SUCCESS); 1451 } 1452 1453 #include <../src/mat/impls/aij/seq/ftn-kernels/fmult.h> 1454 1455 PetscErrorCode MatMult_SeqAIJ(Mat A, Vec xx, Vec yy) 1456 { 1457 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1458 PetscScalar *y; 1459 const PetscScalar *x; 1460 const MatScalar *aa, *a_a; 1461 PetscInt m = A->rmap->n; 1462 const PetscInt *aj, *ii, *ridx = NULL; 1463 PetscInt n, i; 1464 PetscScalar sum; 1465 PetscBool usecprow = a->compressedrow.use; 1466 1467 #if defined(PETSC_HAVE_PRAGMA_DISJOINT) 1468 #pragma disjoint(*x, *y, *aa) 1469 #endif 1470 1471 PetscFunctionBegin; 1472 if (a->inode.use && a->inode.checked) { 1473 PetscCall(MatMult_SeqAIJ_Inode(A, xx, yy)); 1474 PetscFunctionReturn(PETSC_SUCCESS); 1475 } 1476 PetscCall(MatSeqAIJGetArrayRead(A, &a_a)); 1477 PetscCall(VecGetArrayRead(xx, &x)); 1478 PetscCall(VecGetArray(yy, &y)); 1479 ii = a->i; 1480 if (usecprow) { /* use compressed row format */ 1481 PetscCall(PetscArrayzero(y, m)); 1482 m = a->compressedrow.nrows; 1483 ii = a->compressedrow.i; 1484 ridx = a->compressedrow.rindex; 1485 for (i = 0; i < m; i++) { 1486 n = ii[i + 1] - ii[i]; 1487 aj = a->j + ii[i]; 1488 aa = a_a + ii[i]; 1489 sum = 0.0; 1490 PetscSparseDensePlusDot(sum, x, aa, aj, n); 1491 /* for (j=0; j<n; j++) sum += (*aa++)*x[*aj++]; */ 1492 y[*ridx++] = sum; 1493 } 1494 } else { /* do not use compressed row format */ 1495 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTAIJ) 1496 aj = a->j; 1497 aa = a_a; 1498 fortranmultaij_(&m, x, ii, aj, aa, y); 1499 #else 1500 for (i = 0; i < m; i++) { 1501 n = ii[i + 1] - ii[i]; 1502 aj = a->j + ii[i]; 1503 aa = a_a + ii[i]; 1504 sum = 0.0; 1505 PetscSparseDensePlusDot(sum, x, aa, aj, n); 1506 y[i] = sum; 1507 } 1508 #endif 1509 } 1510 PetscCall(PetscLogFlops(2.0 * a->nz - a->nonzerorowcnt)); 1511 PetscCall(VecRestoreArrayRead(xx, &x)); 1512 PetscCall(VecRestoreArray(yy, &y)); 1513 PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a)); 1514 PetscFunctionReturn(PETSC_SUCCESS); 1515 } 1516 1517 PetscErrorCode MatMultMax_SeqAIJ(Mat A, Vec xx, Vec yy) 1518 { 1519 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1520 PetscScalar *y; 1521 const PetscScalar *x; 1522 const MatScalar *aa, *a_a; 1523 PetscInt m = A->rmap->n; 1524 const PetscInt *aj, *ii, *ridx = NULL; 1525 PetscInt n, i, nonzerorow = 0; 1526 PetscScalar sum; 1527 PetscBool usecprow = a->compressedrow.use; 1528 1529 #if defined(PETSC_HAVE_PRAGMA_DISJOINT) 1530 #pragma disjoint(*x, *y, *aa) 1531 #endif 1532 1533 PetscFunctionBegin; 1534 PetscCall(MatSeqAIJGetArrayRead(A, &a_a)); 1535 PetscCall(VecGetArrayRead(xx, &x)); 1536 PetscCall(VecGetArray(yy, &y)); 1537 if (usecprow) { /* use compressed row format */ 1538 m = a->compressedrow.nrows; 1539 ii = a->compressedrow.i; 1540 ridx = a->compressedrow.rindex; 1541 for (i = 0; i < m; i++) { 1542 n = ii[i + 1] - ii[i]; 1543 aj = a->j + ii[i]; 1544 aa = a_a + ii[i]; 1545 sum = 0.0; 1546 nonzerorow += (n > 0); 1547 PetscSparseDenseMaxDot(sum, x, aa, aj, n); 1548 /* for (j=0; j<n; j++) sum += (*aa++)*x[*aj++]; */ 1549 y[*ridx++] = sum; 1550 } 1551 } else { /* do not use compressed row format */ 1552 ii = a->i; 1553 for (i = 0; i < m; i++) { 1554 n = ii[i + 1] - ii[i]; 1555 aj = a->j + ii[i]; 1556 aa = a_a + ii[i]; 1557 sum = 0.0; 1558 nonzerorow += (n > 0); 1559 PetscSparseDenseMaxDot(sum, x, aa, aj, n); 1560 y[i] = sum; 1561 } 1562 } 1563 PetscCall(PetscLogFlops(2.0 * a->nz - nonzerorow)); 1564 PetscCall(VecRestoreArrayRead(xx, &x)); 1565 PetscCall(VecRestoreArray(yy, &y)); 1566 PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a)); 1567 PetscFunctionReturn(PETSC_SUCCESS); 1568 } 1569 1570 PetscErrorCode MatMultAddMax_SeqAIJ(Mat A, Vec xx, Vec yy, Vec zz) 1571 { 1572 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1573 PetscScalar *y, *z; 1574 const PetscScalar *x; 1575 const MatScalar *aa, *a_a; 1576 PetscInt m = A->rmap->n, *aj, *ii; 1577 PetscInt n, i, *ridx = NULL; 1578 PetscScalar sum; 1579 PetscBool usecprow = a->compressedrow.use; 1580 1581 PetscFunctionBegin; 1582 PetscCall(MatSeqAIJGetArrayRead(A, &a_a)); 1583 PetscCall(VecGetArrayRead(xx, &x)); 1584 PetscCall(VecGetArrayPair(yy, zz, &y, &z)); 1585 if (usecprow) { /* use compressed row format */ 1586 if (zz != yy) PetscCall(PetscArraycpy(z, y, m)); 1587 m = a->compressedrow.nrows; 1588 ii = a->compressedrow.i; 1589 ridx = a->compressedrow.rindex; 1590 for (i = 0; i < m; i++) { 1591 n = ii[i + 1] - ii[i]; 1592 aj = a->j + ii[i]; 1593 aa = a_a + ii[i]; 1594 sum = y[*ridx]; 1595 PetscSparseDenseMaxDot(sum, x, aa, aj, n); 1596 z[*ridx++] = sum; 1597 } 1598 } else { /* do not use compressed row format */ 1599 ii = a->i; 1600 for (i = 0; i < m; i++) { 1601 n = ii[i + 1] - ii[i]; 1602 aj = a->j + ii[i]; 1603 aa = a_a + ii[i]; 1604 sum = y[i]; 1605 PetscSparseDenseMaxDot(sum, x, aa, aj, n); 1606 z[i] = sum; 1607 } 1608 } 1609 PetscCall(PetscLogFlops(2.0 * a->nz)); 1610 PetscCall(VecRestoreArrayRead(xx, &x)); 1611 PetscCall(VecRestoreArrayPair(yy, zz, &y, &z)); 1612 PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a)); 1613 PetscFunctionReturn(PETSC_SUCCESS); 1614 } 1615 1616 #include <../src/mat/impls/aij/seq/ftn-kernels/fmultadd.h> 1617 PetscErrorCode MatMultAdd_SeqAIJ(Mat A, Vec xx, Vec yy, Vec zz) 1618 { 1619 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1620 PetscScalar *y, *z; 1621 const PetscScalar *x; 1622 const MatScalar *aa, *a_a; 1623 const PetscInt *aj, *ii, *ridx = NULL; 1624 PetscInt m = A->rmap->n, n, i; 1625 PetscScalar sum; 1626 PetscBool usecprow = a->compressedrow.use; 1627 1628 PetscFunctionBegin; 1629 if (a->inode.use && a->inode.checked) { 1630 PetscCall(MatMultAdd_SeqAIJ_Inode(A, xx, yy, zz)); 1631 PetscFunctionReturn(PETSC_SUCCESS); 1632 } 1633 PetscCall(MatSeqAIJGetArrayRead(A, &a_a)); 1634 PetscCall(VecGetArrayRead(xx, &x)); 1635 PetscCall(VecGetArrayPair(yy, zz, &y, &z)); 1636 if (usecprow) { /* use compressed row format */ 1637 if (zz != yy) PetscCall(PetscArraycpy(z, y, m)); 1638 m = a->compressedrow.nrows; 1639 ii = a->compressedrow.i; 1640 ridx = a->compressedrow.rindex; 1641 for (i = 0; i < m; i++) { 1642 n = ii[i + 1] - ii[i]; 1643 aj = a->j + ii[i]; 1644 aa = a_a + ii[i]; 1645 sum = y[*ridx]; 1646 PetscSparseDensePlusDot(sum, x, aa, aj, n); 1647 z[*ridx++] = sum; 1648 } 1649 } else { /* do not use compressed row format */ 1650 ii = a->i; 1651 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTADDAIJ) 1652 aj = a->j; 1653 aa = a_a; 1654 fortranmultaddaij_(&m, x, ii, aj, aa, y, z); 1655 #else 1656 for (i = 0; i < m; i++) { 1657 n = ii[i + 1] - ii[i]; 1658 aj = a->j + ii[i]; 1659 aa = a_a + ii[i]; 1660 sum = y[i]; 1661 PetscSparseDensePlusDot(sum, x, aa, aj, n); 1662 z[i] = sum; 1663 } 1664 #endif 1665 } 1666 PetscCall(PetscLogFlops(2.0 * a->nz)); 1667 PetscCall(VecRestoreArrayRead(xx, &x)); 1668 PetscCall(VecRestoreArrayPair(yy, zz, &y, &z)); 1669 PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a)); 1670 PetscFunctionReturn(PETSC_SUCCESS); 1671 } 1672 1673 /* 1674 Adds diagonal pointers to sparse matrix structure. 1675 */ 1676 PetscErrorCode MatMarkDiagonal_SeqAIJ(Mat A) 1677 { 1678 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1679 PetscInt i, j, m = A->rmap->n; 1680 PetscBool alreadySet = PETSC_TRUE; 1681 1682 PetscFunctionBegin; 1683 if (!a->diag) { 1684 PetscCall(PetscMalloc1(m, &a->diag)); 1685 alreadySet = PETSC_FALSE; 1686 } 1687 for (i = 0; i < A->rmap->n; i++) { 1688 /* If A's diagonal is already correctly set, this fast track enables cheap and repeated MatMarkDiagonal_SeqAIJ() calls */ 1689 if (alreadySet) { 1690 PetscInt pos = a->diag[i]; 1691 if (pos >= a->i[i] && pos < a->i[i + 1] && a->j[pos] == i) continue; 1692 } 1693 1694 a->diag[i] = a->i[i + 1]; 1695 for (j = a->i[i]; j < a->i[i + 1]; j++) { 1696 if (a->j[j] == i) { 1697 a->diag[i] = j; 1698 break; 1699 } 1700 } 1701 } 1702 PetscFunctionReturn(PETSC_SUCCESS); 1703 } 1704 1705 PetscErrorCode MatShift_SeqAIJ(Mat A, PetscScalar v) 1706 { 1707 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1708 const PetscInt *diag = (const PetscInt *)a->diag; 1709 const PetscInt *ii = (const PetscInt *)a->i; 1710 PetscInt i, *mdiag = NULL; 1711 PetscInt cnt = 0; /* how many diagonals are missing */ 1712 1713 PetscFunctionBegin; 1714 if (!A->preallocated || !a->nz) { 1715 PetscCall(MatSeqAIJSetPreallocation(A, 1, NULL)); 1716 PetscCall(MatShift_Basic(A, v)); 1717 PetscFunctionReturn(PETSC_SUCCESS); 1718 } 1719 1720 if (a->diagonaldense) { 1721 cnt = 0; 1722 } else { 1723 PetscCall(PetscCalloc1(A->rmap->n, &mdiag)); 1724 for (i = 0; i < A->rmap->n; i++) { 1725 if (i < A->cmap->n && diag[i] >= ii[i + 1]) { /* 'out of range' rows never have diagonals */ 1726 cnt++; 1727 mdiag[i] = 1; 1728 } 1729 } 1730 } 1731 if (!cnt) { 1732 PetscCall(MatShift_Basic(A, v)); 1733 } else { 1734 PetscScalar *olda = a->a; /* preserve pointers to current matrix nonzeros structure and values */ 1735 PetscInt *oldj = a->j, *oldi = a->i; 1736 PetscBool singlemalloc = a->singlemalloc, free_a = a->free_a, free_ij = a->free_ij; 1737 1738 a->a = NULL; 1739 a->j = NULL; 1740 a->i = NULL; 1741 /* increase the values in imax for each row where a diagonal is being inserted then reallocate the matrix data structures */ 1742 for (i = 0; i < PetscMin(A->rmap->n, A->cmap->n); i++) a->imax[i] += mdiag[i]; 1743 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(A, 0, a->imax)); 1744 1745 /* copy old values into new matrix data structure */ 1746 for (i = 0; i < A->rmap->n; i++) { 1747 PetscCall(MatSetValues(A, 1, &i, a->imax[i] - mdiag[i], &oldj[oldi[i]], &olda[oldi[i]], ADD_VALUES)); 1748 if (i < A->cmap->n) PetscCall(MatSetValue(A, i, i, v, ADD_VALUES)); 1749 } 1750 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 1751 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 1752 if (singlemalloc) { 1753 PetscCall(PetscFree3(olda, oldj, oldi)); 1754 } else { 1755 if (free_a) PetscCall(PetscFree(olda)); 1756 if (free_ij) PetscCall(PetscFree(oldj)); 1757 if (free_ij) PetscCall(PetscFree(oldi)); 1758 } 1759 } 1760 PetscCall(PetscFree(mdiag)); 1761 a->diagonaldense = PETSC_TRUE; 1762 PetscFunctionReturn(PETSC_SUCCESS); 1763 } 1764 1765 /* 1766 Checks for missing diagonals 1767 */ 1768 PetscErrorCode MatMissingDiagonal_SeqAIJ(Mat A, PetscBool *missing, PetscInt *d) 1769 { 1770 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1771 PetscInt *diag, *ii = a->i, i; 1772 1773 PetscFunctionBegin; 1774 *missing = PETSC_FALSE; 1775 if (A->rmap->n > 0 && !ii) { 1776 *missing = PETSC_TRUE; 1777 if (d) *d = 0; 1778 PetscCall(PetscInfo(A, "Matrix has no entries therefore is missing diagonal\n")); 1779 } else { 1780 PetscInt n; 1781 n = PetscMin(A->rmap->n, A->cmap->n); 1782 diag = a->diag; 1783 for (i = 0; i < n; i++) { 1784 if (diag[i] >= ii[i + 1]) { 1785 *missing = PETSC_TRUE; 1786 if (d) *d = i; 1787 PetscCall(PetscInfo(A, "Matrix is missing diagonal number %" PetscInt_FMT "\n", i)); 1788 break; 1789 } 1790 } 1791 } 1792 PetscFunctionReturn(PETSC_SUCCESS); 1793 } 1794 1795 #include <petscblaslapack.h> 1796 #include <petsc/private/kernels/blockinvert.h> 1797 1798 /* 1799 Note that values is allocated externally by the PC and then passed into this routine 1800 */ 1801 PetscErrorCode MatInvertVariableBlockDiagonal_SeqAIJ(Mat A, PetscInt nblocks, const PetscInt *bsizes, PetscScalar *diag) 1802 { 1803 PetscInt n = A->rmap->n, i, ncnt = 0, *indx, j, bsizemax = 0, *v_pivots; 1804 PetscBool allowzeropivot, zeropivotdetected = PETSC_FALSE; 1805 const PetscReal shift = 0.0; 1806 PetscInt ipvt[5]; 1807 PetscCount flops = 0; 1808 PetscScalar work[25], *v_work; 1809 1810 PetscFunctionBegin; 1811 allowzeropivot = PetscNot(A->erroriffailure); 1812 for (i = 0; i < nblocks; i++) ncnt += bsizes[i]; 1813 PetscCheck(ncnt == n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total blocksizes %" PetscInt_FMT " doesn't match number matrix rows %" PetscInt_FMT, ncnt, n); 1814 for (i = 0; i < nblocks; i++) bsizemax = PetscMax(bsizemax, bsizes[i]); 1815 PetscCall(PetscMalloc1(bsizemax, &indx)); 1816 if (bsizemax > 7) PetscCall(PetscMalloc2(bsizemax, &v_work, bsizemax, &v_pivots)); 1817 ncnt = 0; 1818 for (i = 0; i < nblocks; i++) { 1819 for (j = 0; j < bsizes[i]; j++) indx[j] = ncnt + j; 1820 PetscCall(MatGetValues(A, bsizes[i], indx, bsizes[i], indx, diag)); 1821 switch (bsizes[i]) { 1822 case 1: 1823 *diag = 1.0 / (*diag); 1824 break; 1825 case 2: 1826 PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected)); 1827 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1828 PetscCall(PetscKernel_A_gets_transpose_A_2(diag)); 1829 break; 1830 case 3: 1831 PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected)); 1832 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1833 PetscCall(PetscKernel_A_gets_transpose_A_3(diag)); 1834 break; 1835 case 4: 1836 PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected)); 1837 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1838 PetscCall(PetscKernel_A_gets_transpose_A_4(diag)); 1839 break; 1840 case 5: 1841 PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected)); 1842 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1843 PetscCall(PetscKernel_A_gets_transpose_A_5(diag)); 1844 break; 1845 case 6: 1846 PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected)); 1847 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1848 PetscCall(PetscKernel_A_gets_transpose_A_6(diag)); 1849 break; 1850 case 7: 1851 PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected)); 1852 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1853 PetscCall(PetscKernel_A_gets_transpose_A_7(diag)); 1854 break; 1855 default: 1856 PetscCall(PetscKernel_A_gets_inverse_A(bsizes[i], diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected)); 1857 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1858 PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bsizes[i])); 1859 } 1860 ncnt += bsizes[i]; 1861 diag += bsizes[i] * bsizes[i]; 1862 flops += 2 * PetscPowInt(bsizes[i], 3) / 3; 1863 } 1864 PetscCall(PetscLogFlops(flops)); 1865 if (bsizemax > 7) PetscCall(PetscFree2(v_work, v_pivots)); 1866 PetscCall(PetscFree(indx)); 1867 PetscFunctionReturn(PETSC_SUCCESS); 1868 } 1869 1870 /* 1871 Negative shift indicates do not generate an error if there is a zero diagonal, just invert it anyways 1872 */ 1873 PetscErrorCode MatInvertDiagonal_SeqAIJ(Mat A, PetscScalar omega, PetscScalar fshift) 1874 { 1875 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1876 PetscInt i, *diag, m = A->rmap->n; 1877 const MatScalar *v; 1878 PetscScalar *idiag, *mdiag; 1879 1880 PetscFunctionBegin; 1881 if (a->idiagvalid) PetscFunctionReturn(PETSC_SUCCESS); 1882 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 1883 diag = a->diag; 1884 if (!a->idiag) { PetscCall(PetscMalloc3(m, &a->idiag, m, &a->mdiag, m, &a->ssor_work)); } 1885 1886 mdiag = a->mdiag; 1887 idiag = a->idiag; 1888 PetscCall(MatSeqAIJGetArrayRead(A, &v)); 1889 if (omega == 1.0 && PetscRealPart(fshift) <= 0.0) { 1890 for (i = 0; i < m; i++) { 1891 mdiag[i] = v[diag[i]]; 1892 if (!PetscAbsScalar(mdiag[i])) { /* zero diagonal */ 1893 if (PetscRealPart(fshift)) { 1894 PetscCall(PetscInfo(A, "Zero diagonal on row %" PetscInt_FMT "\n", i)); 1895 A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 1896 A->factorerror_zeropivot_value = 0.0; 1897 A->factorerror_zeropivot_row = i; 1898 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Zero diagonal on row %" PetscInt_FMT, i); 1899 } 1900 idiag[i] = 1.0 / v[diag[i]]; 1901 } 1902 PetscCall(PetscLogFlops(m)); 1903 } else { 1904 for (i = 0; i < m; i++) { 1905 mdiag[i] = v[diag[i]]; 1906 idiag[i] = omega / (fshift + v[diag[i]]); 1907 } 1908 PetscCall(PetscLogFlops(2.0 * m)); 1909 } 1910 a->idiagvalid = PETSC_TRUE; 1911 PetscCall(MatSeqAIJRestoreArrayRead(A, &v)); 1912 PetscFunctionReturn(PETSC_SUCCESS); 1913 } 1914 1915 #include <../src/mat/impls/aij/seq/ftn-kernels/frelax.h> 1916 PetscErrorCode MatSOR_SeqAIJ(Mat A, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx) 1917 { 1918 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 1919 PetscScalar *x, d, sum, *t, scale; 1920 const MatScalar *v, *idiag = NULL, *mdiag, *aa; 1921 const PetscScalar *b, *bs, *xb, *ts; 1922 PetscInt n, m = A->rmap->n, i; 1923 const PetscInt *idx, *diag; 1924 1925 PetscFunctionBegin; 1926 if (a->inode.use && a->inode.checked && omega == 1.0 && fshift == 0.0) { 1927 PetscCall(MatSOR_SeqAIJ_Inode(A, bb, omega, flag, fshift, its, lits, xx)); 1928 PetscFunctionReturn(PETSC_SUCCESS); 1929 } 1930 its = its * lits; 1931 1932 if (fshift != a->fshift || omega != a->omega) a->idiagvalid = PETSC_FALSE; /* must recompute idiag[] */ 1933 if (!a->idiagvalid) PetscCall(MatInvertDiagonal_SeqAIJ(A, omega, fshift)); 1934 a->fshift = fshift; 1935 a->omega = omega; 1936 1937 diag = a->diag; 1938 t = a->ssor_work; 1939 idiag = a->idiag; 1940 mdiag = a->mdiag; 1941 1942 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 1943 PetscCall(VecGetArray(xx, &x)); 1944 PetscCall(VecGetArrayRead(bb, &b)); 1945 /* We count flops by assuming the upper triangular and lower triangular parts have the same number of nonzeros */ 1946 if (flag == SOR_APPLY_UPPER) { 1947 /* apply (U + D/omega) to the vector */ 1948 bs = b; 1949 for (i = 0; i < m; i++) { 1950 d = fshift + mdiag[i]; 1951 n = a->i[i + 1] - diag[i] - 1; 1952 idx = a->j + diag[i] + 1; 1953 v = aa + diag[i] + 1; 1954 sum = b[i] * d / omega; 1955 PetscSparseDensePlusDot(sum, bs, v, idx, n); 1956 x[i] = sum; 1957 } 1958 PetscCall(VecRestoreArray(xx, &x)); 1959 PetscCall(VecRestoreArrayRead(bb, &b)); 1960 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 1961 PetscCall(PetscLogFlops(a->nz)); 1962 PetscFunctionReturn(PETSC_SUCCESS); 1963 } 1964 1965 PetscCheck(flag != SOR_APPLY_LOWER, PETSC_COMM_SELF, PETSC_ERR_SUP, "SOR_APPLY_LOWER is not implemented"); 1966 if (flag & SOR_EISENSTAT) { 1967 /* Let A = L + U + D; where L is lower triangular, 1968 U is upper triangular, E = D/omega; This routine applies 1969 1970 (L + E)^{-1} A (U + E)^{-1} 1971 1972 to a vector efficiently using Eisenstat's trick. 1973 */ 1974 scale = (2.0 / omega) - 1.0; 1975 1976 /* x = (E + U)^{-1} b */ 1977 for (i = m - 1; i >= 0; i--) { 1978 n = a->i[i + 1] - diag[i] - 1; 1979 idx = a->j + diag[i] + 1; 1980 v = aa + diag[i] + 1; 1981 sum = b[i]; 1982 PetscSparseDenseMinusDot(sum, x, v, idx, n); 1983 x[i] = sum * idiag[i]; 1984 } 1985 1986 /* t = b - (2*E - D)x */ 1987 v = aa; 1988 for (i = 0; i < m; i++) t[i] = b[i] - scale * (v[*diag++]) * x[i]; 1989 1990 /* t = (E + L)^{-1}t */ 1991 ts = t; 1992 diag = a->diag; 1993 for (i = 0; i < m; i++) { 1994 n = diag[i] - a->i[i]; 1995 idx = a->j + a->i[i]; 1996 v = aa + a->i[i]; 1997 sum = t[i]; 1998 PetscSparseDenseMinusDot(sum, ts, v, idx, n); 1999 t[i] = sum * idiag[i]; 2000 /* x = x + t */ 2001 x[i] += t[i]; 2002 } 2003 2004 PetscCall(PetscLogFlops(6.0 * m - 1 + 2.0 * a->nz)); 2005 PetscCall(VecRestoreArray(xx, &x)); 2006 PetscCall(VecRestoreArrayRead(bb, &b)); 2007 PetscFunctionReturn(PETSC_SUCCESS); 2008 } 2009 if (flag & SOR_ZERO_INITIAL_GUESS) { 2010 if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) { 2011 for (i = 0; i < m; i++) { 2012 n = diag[i] - a->i[i]; 2013 idx = a->j + a->i[i]; 2014 v = aa + a->i[i]; 2015 sum = b[i]; 2016 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2017 t[i] = sum; 2018 x[i] = sum * idiag[i]; 2019 } 2020 xb = t; 2021 PetscCall(PetscLogFlops(a->nz)); 2022 } else xb = b; 2023 if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) { 2024 for (i = m - 1; i >= 0; i--) { 2025 n = a->i[i + 1] - diag[i] - 1; 2026 idx = a->j + diag[i] + 1; 2027 v = aa + diag[i] + 1; 2028 sum = xb[i]; 2029 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2030 if (xb == b) { 2031 x[i] = sum * idiag[i]; 2032 } else { 2033 x[i] = (1 - omega) * x[i] + sum * idiag[i]; /* omega in idiag */ 2034 } 2035 } 2036 PetscCall(PetscLogFlops(a->nz)); /* assumes 1/2 in upper */ 2037 } 2038 its--; 2039 } 2040 while (its--) { 2041 if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) { 2042 for (i = 0; i < m; i++) { 2043 /* lower */ 2044 n = diag[i] - a->i[i]; 2045 idx = a->j + a->i[i]; 2046 v = aa + a->i[i]; 2047 sum = b[i]; 2048 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2049 t[i] = sum; /* save application of the lower-triangular part */ 2050 /* upper */ 2051 n = a->i[i + 1] - diag[i] - 1; 2052 idx = a->j + diag[i] + 1; 2053 v = aa + diag[i] + 1; 2054 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2055 x[i] = (1. - omega) * x[i] + sum * idiag[i]; /* omega in idiag */ 2056 } 2057 xb = t; 2058 PetscCall(PetscLogFlops(2.0 * a->nz)); 2059 } else xb = b; 2060 if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) { 2061 for (i = m - 1; i >= 0; i--) { 2062 sum = xb[i]; 2063 if (xb == b) { 2064 /* whole matrix (no checkpointing available) */ 2065 n = a->i[i + 1] - a->i[i]; 2066 idx = a->j + a->i[i]; 2067 v = aa + a->i[i]; 2068 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2069 x[i] = (1. - omega) * x[i] + (sum + mdiag[i] * x[i]) * idiag[i]; 2070 } else { /* lower-triangular part has been saved, so only apply upper-triangular */ 2071 n = a->i[i + 1] - diag[i] - 1; 2072 idx = a->j + diag[i] + 1; 2073 v = aa + diag[i] + 1; 2074 PetscSparseDenseMinusDot(sum, x, v, idx, n); 2075 x[i] = (1. - omega) * x[i] + sum * idiag[i]; /* omega in idiag */ 2076 } 2077 } 2078 if (xb == b) { 2079 PetscCall(PetscLogFlops(2.0 * a->nz)); 2080 } else { 2081 PetscCall(PetscLogFlops(a->nz)); /* assumes 1/2 in upper */ 2082 } 2083 } 2084 } 2085 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2086 PetscCall(VecRestoreArray(xx, &x)); 2087 PetscCall(VecRestoreArrayRead(bb, &b)); 2088 PetscFunctionReturn(PETSC_SUCCESS); 2089 } 2090 2091 PetscErrorCode MatGetInfo_SeqAIJ(Mat A, MatInfoType flag, MatInfo *info) 2092 { 2093 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2094 2095 PetscFunctionBegin; 2096 info->block_size = 1.0; 2097 info->nz_allocated = a->maxnz; 2098 info->nz_used = a->nz; 2099 info->nz_unneeded = (a->maxnz - a->nz); 2100 info->assemblies = A->num_ass; 2101 info->mallocs = A->info.mallocs; 2102 info->memory = 0; /* REVIEW ME */ 2103 if (A->factortype) { 2104 info->fill_ratio_given = A->info.fill_ratio_given; 2105 info->fill_ratio_needed = A->info.fill_ratio_needed; 2106 info->factor_mallocs = A->info.factor_mallocs; 2107 } else { 2108 info->fill_ratio_given = 0; 2109 info->fill_ratio_needed = 0; 2110 info->factor_mallocs = 0; 2111 } 2112 PetscFunctionReturn(PETSC_SUCCESS); 2113 } 2114 2115 PetscErrorCode MatZeroRows_SeqAIJ(Mat A, PetscInt N, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 2116 { 2117 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2118 PetscInt i, m = A->rmap->n - 1; 2119 const PetscScalar *xx; 2120 PetscScalar *bb, *aa; 2121 PetscInt d = 0; 2122 2123 PetscFunctionBegin; 2124 if (x && b) { 2125 PetscCall(VecGetArrayRead(x, &xx)); 2126 PetscCall(VecGetArray(b, &bb)); 2127 for (i = 0; i < N; i++) { 2128 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2129 if (rows[i] >= A->cmap->n) continue; 2130 bb[rows[i]] = diag * xx[rows[i]]; 2131 } 2132 PetscCall(VecRestoreArrayRead(x, &xx)); 2133 PetscCall(VecRestoreArray(b, &bb)); 2134 } 2135 2136 PetscCall(MatSeqAIJGetArray(A, &aa)); 2137 if (a->keepnonzeropattern) { 2138 for (i = 0; i < N; i++) { 2139 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2140 PetscCall(PetscArrayzero(&aa[a->i[rows[i]]], a->ilen[rows[i]])); 2141 } 2142 if (diag != 0.0) { 2143 for (i = 0; i < N; i++) { 2144 d = rows[i]; 2145 if (rows[i] >= A->cmap->n) continue; 2146 PetscCheck(a->diag[d] < a->i[d + 1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Matrix is missing diagonal entry in the zeroed row %" PetscInt_FMT, d); 2147 } 2148 for (i = 0; i < N; i++) { 2149 if (rows[i] >= A->cmap->n) continue; 2150 aa[a->diag[rows[i]]] = diag; 2151 } 2152 } 2153 } else { 2154 if (diag != 0.0) { 2155 for (i = 0; i < N; i++) { 2156 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2157 if (a->ilen[rows[i]] > 0) { 2158 if (rows[i] >= A->cmap->n) { 2159 a->ilen[rows[i]] = 0; 2160 } else { 2161 a->ilen[rows[i]] = 1; 2162 aa[a->i[rows[i]]] = diag; 2163 a->j[a->i[rows[i]]] = rows[i]; 2164 } 2165 } else if (rows[i] < A->cmap->n) { /* in case row was completely empty */ 2166 PetscCall(MatSetValues_SeqAIJ(A, 1, &rows[i], 1, &rows[i], &diag, INSERT_VALUES)); 2167 } 2168 } 2169 } else { 2170 for (i = 0; i < N; i++) { 2171 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2172 a->ilen[rows[i]] = 0; 2173 } 2174 } 2175 A->nonzerostate++; 2176 } 2177 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 2178 PetscUseTypeMethod(A, assemblyend, MAT_FINAL_ASSEMBLY); 2179 PetscFunctionReturn(PETSC_SUCCESS); 2180 } 2181 2182 PetscErrorCode MatZeroRowsColumns_SeqAIJ(Mat A, PetscInt N, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 2183 { 2184 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2185 PetscInt i, j, m = A->rmap->n - 1, d = 0; 2186 PetscBool missing, *zeroed, vecs = PETSC_FALSE; 2187 const PetscScalar *xx; 2188 PetscScalar *bb, *aa; 2189 2190 PetscFunctionBegin; 2191 if (!N) PetscFunctionReturn(PETSC_SUCCESS); 2192 PetscCall(MatSeqAIJGetArray(A, &aa)); 2193 if (x && b) { 2194 PetscCall(VecGetArrayRead(x, &xx)); 2195 PetscCall(VecGetArray(b, &bb)); 2196 vecs = PETSC_TRUE; 2197 } 2198 PetscCall(PetscCalloc1(A->rmap->n, &zeroed)); 2199 for (i = 0; i < N; i++) { 2200 PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]); 2201 PetscCall(PetscArrayzero(&aa[a->i[rows[i]]], a->ilen[rows[i]])); 2202 2203 zeroed[rows[i]] = PETSC_TRUE; 2204 } 2205 for (i = 0; i < A->rmap->n; i++) { 2206 if (!zeroed[i]) { 2207 for (j = a->i[i]; j < a->i[i + 1]; j++) { 2208 if (a->j[j] < A->rmap->n && zeroed[a->j[j]]) { 2209 if (vecs) bb[i] -= aa[j] * xx[a->j[j]]; 2210 aa[j] = 0.0; 2211 } 2212 } 2213 } else if (vecs && i < A->cmap->N) bb[i] = diag * xx[i]; 2214 } 2215 if (x && b) { 2216 PetscCall(VecRestoreArrayRead(x, &xx)); 2217 PetscCall(VecRestoreArray(b, &bb)); 2218 } 2219 PetscCall(PetscFree(zeroed)); 2220 if (diag != 0.0) { 2221 PetscCall(MatMissingDiagonal_SeqAIJ(A, &missing, &d)); 2222 if (missing) { 2223 for (i = 0; i < N; i++) { 2224 if (rows[i] >= A->cmap->N) continue; 2225 PetscCheck(!a->nonew || rows[i] < d, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Matrix is missing diagonal entry in row %" PetscInt_FMT " (%" PetscInt_FMT ")", d, rows[i]); 2226 PetscCall(MatSetValues_SeqAIJ(A, 1, &rows[i], 1, &rows[i], &diag, INSERT_VALUES)); 2227 } 2228 } else { 2229 for (i = 0; i < N; i++) aa[a->diag[rows[i]]] = diag; 2230 } 2231 } 2232 PetscCall(MatSeqAIJRestoreArray(A, &aa)); 2233 PetscUseTypeMethod(A, assemblyend, MAT_FINAL_ASSEMBLY); 2234 PetscFunctionReturn(PETSC_SUCCESS); 2235 } 2236 2237 PetscErrorCode MatGetRow_SeqAIJ(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v) 2238 { 2239 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2240 const PetscScalar *aa; 2241 PetscInt *itmp; 2242 2243 PetscFunctionBegin; 2244 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2245 *nz = a->i[row + 1] - a->i[row]; 2246 if (v) *v = (PetscScalar *)(aa + a->i[row]); 2247 if (idx) { 2248 itmp = a->j + a->i[row]; 2249 if (*nz) *idx = itmp; 2250 else *idx = NULL; 2251 } 2252 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2253 PetscFunctionReturn(PETSC_SUCCESS); 2254 } 2255 2256 PetscErrorCode MatRestoreRow_SeqAIJ(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v) 2257 { 2258 PetscFunctionBegin; 2259 if (nz) *nz = 0; 2260 if (idx) *idx = NULL; 2261 if (v) *v = NULL; 2262 PetscFunctionReturn(PETSC_SUCCESS); 2263 } 2264 2265 PetscErrorCode MatNorm_SeqAIJ(Mat A, NormType type, PetscReal *nrm) 2266 { 2267 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2268 const MatScalar *v; 2269 PetscReal sum = 0.0; 2270 PetscInt i, j; 2271 2272 PetscFunctionBegin; 2273 PetscCall(MatSeqAIJGetArrayRead(A, &v)); 2274 if (type == NORM_FROBENIUS) { 2275 #if defined(PETSC_USE_REAL___FP16) 2276 PetscBLASInt one = 1, nz = a->nz; 2277 PetscCallBLAS("BLASnrm2", *nrm = BLASnrm2_(&nz, v, &one)); 2278 #else 2279 for (i = 0; i < a->nz; i++) { 2280 sum += PetscRealPart(PetscConj(*v) * (*v)); 2281 v++; 2282 } 2283 *nrm = PetscSqrtReal(sum); 2284 #endif 2285 PetscCall(PetscLogFlops(2.0 * a->nz)); 2286 } else if (type == NORM_1) { 2287 PetscReal *tmp; 2288 PetscInt *jj = a->j; 2289 PetscCall(PetscCalloc1(A->cmap->n + 1, &tmp)); 2290 *nrm = 0.0; 2291 for (j = 0; j < a->nz; j++) { 2292 tmp[*jj++] += PetscAbsScalar(*v); 2293 v++; 2294 } 2295 for (j = 0; j < A->cmap->n; j++) { 2296 if (tmp[j] > *nrm) *nrm = tmp[j]; 2297 } 2298 PetscCall(PetscFree(tmp)); 2299 PetscCall(PetscLogFlops(PetscMax(a->nz - 1, 0))); 2300 } else if (type == NORM_INFINITY) { 2301 *nrm = 0.0; 2302 for (j = 0; j < A->rmap->n; j++) { 2303 const PetscScalar *v2 = v + a->i[j]; 2304 sum = 0.0; 2305 for (i = 0; i < a->i[j + 1] - a->i[j]; i++) { 2306 sum += PetscAbsScalar(*v2); 2307 v2++; 2308 } 2309 if (sum > *nrm) *nrm = sum; 2310 } 2311 PetscCall(PetscLogFlops(PetscMax(a->nz - 1, 0))); 2312 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for two norm"); 2313 PetscCall(MatSeqAIJRestoreArrayRead(A, &v)); 2314 PetscFunctionReturn(PETSC_SUCCESS); 2315 } 2316 2317 PetscErrorCode MatIsTranspose_SeqAIJ(Mat A, Mat B, PetscReal tol, PetscBool *f) 2318 { 2319 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data, *bij = (Mat_SeqAIJ *)B->data; 2320 PetscInt *adx, *bdx, *aii, *bii, *aptr, *bptr; 2321 const MatScalar *va, *vb; 2322 PetscInt ma, na, mb, nb, i; 2323 2324 PetscFunctionBegin; 2325 PetscCall(MatGetSize(A, &ma, &na)); 2326 PetscCall(MatGetSize(B, &mb, &nb)); 2327 if (ma != nb || na != mb) { 2328 *f = PETSC_FALSE; 2329 PetscFunctionReturn(PETSC_SUCCESS); 2330 } 2331 PetscCall(MatSeqAIJGetArrayRead(A, &va)); 2332 PetscCall(MatSeqAIJGetArrayRead(B, &vb)); 2333 aii = aij->i; 2334 bii = bij->i; 2335 adx = aij->j; 2336 bdx = bij->j; 2337 PetscCall(PetscMalloc1(ma, &aptr)); 2338 PetscCall(PetscMalloc1(mb, &bptr)); 2339 for (i = 0; i < ma; i++) aptr[i] = aii[i]; 2340 for (i = 0; i < mb; i++) bptr[i] = bii[i]; 2341 2342 *f = PETSC_TRUE; 2343 for (i = 0; i < ma; i++) { 2344 while (aptr[i] < aii[i + 1]) { 2345 PetscInt idc, idr; 2346 PetscScalar vc, vr; 2347 /* column/row index/value */ 2348 idc = adx[aptr[i]]; 2349 idr = bdx[bptr[idc]]; 2350 vc = va[aptr[i]]; 2351 vr = vb[bptr[idc]]; 2352 if (i != idr || PetscAbsScalar(vc - vr) > tol) { 2353 *f = PETSC_FALSE; 2354 goto done; 2355 } else { 2356 aptr[i]++; 2357 if (B || i != idc) bptr[idc]++; 2358 } 2359 } 2360 } 2361 done: 2362 PetscCall(PetscFree(aptr)); 2363 PetscCall(PetscFree(bptr)); 2364 PetscCall(MatSeqAIJRestoreArrayRead(A, &va)); 2365 PetscCall(MatSeqAIJRestoreArrayRead(B, &vb)); 2366 PetscFunctionReturn(PETSC_SUCCESS); 2367 } 2368 2369 PetscErrorCode MatIsHermitianTranspose_SeqAIJ(Mat A, Mat B, PetscReal tol, PetscBool *f) 2370 { 2371 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data, *bij = (Mat_SeqAIJ *)B->data; 2372 PetscInt *adx, *bdx, *aii, *bii, *aptr, *bptr; 2373 MatScalar *va, *vb; 2374 PetscInt ma, na, mb, nb, i; 2375 2376 PetscFunctionBegin; 2377 PetscCall(MatGetSize(A, &ma, &na)); 2378 PetscCall(MatGetSize(B, &mb, &nb)); 2379 if (ma != nb || na != mb) { 2380 *f = PETSC_FALSE; 2381 PetscFunctionReturn(PETSC_SUCCESS); 2382 } 2383 aii = aij->i; 2384 bii = bij->i; 2385 adx = aij->j; 2386 bdx = bij->j; 2387 va = aij->a; 2388 vb = bij->a; 2389 PetscCall(PetscMalloc1(ma, &aptr)); 2390 PetscCall(PetscMalloc1(mb, &bptr)); 2391 for (i = 0; i < ma; i++) aptr[i] = aii[i]; 2392 for (i = 0; i < mb; i++) bptr[i] = bii[i]; 2393 2394 *f = PETSC_TRUE; 2395 for (i = 0; i < ma; i++) { 2396 while (aptr[i] < aii[i + 1]) { 2397 PetscInt idc, idr; 2398 PetscScalar vc, vr; 2399 /* column/row index/value */ 2400 idc = adx[aptr[i]]; 2401 idr = bdx[bptr[idc]]; 2402 vc = va[aptr[i]]; 2403 vr = vb[bptr[idc]]; 2404 if (i != idr || PetscAbsScalar(vc - PetscConj(vr)) > tol) { 2405 *f = PETSC_FALSE; 2406 goto done; 2407 } else { 2408 aptr[i]++; 2409 if (B || i != idc) bptr[idc]++; 2410 } 2411 } 2412 } 2413 done: 2414 PetscCall(PetscFree(aptr)); 2415 PetscCall(PetscFree(bptr)); 2416 PetscFunctionReturn(PETSC_SUCCESS); 2417 } 2418 2419 PetscErrorCode MatIsSymmetric_SeqAIJ(Mat A, PetscReal tol, PetscBool *f) 2420 { 2421 PetscFunctionBegin; 2422 PetscCall(MatIsTranspose_SeqAIJ(A, A, tol, f)); 2423 PetscFunctionReturn(PETSC_SUCCESS); 2424 } 2425 2426 PetscErrorCode MatIsHermitian_SeqAIJ(Mat A, PetscReal tol, PetscBool *f) 2427 { 2428 PetscFunctionBegin; 2429 PetscCall(MatIsHermitianTranspose_SeqAIJ(A, A, tol, f)); 2430 PetscFunctionReturn(PETSC_SUCCESS); 2431 } 2432 2433 PetscErrorCode MatDiagonalScale_SeqAIJ(Mat A, Vec ll, Vec rr) 2434 { 2435 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2436 const PetscScalar *l, *r; 2437 PetscScalar x; 2438 MatScalar *v; 2439 PetscInt i, j, m = A->rmap->n, n = A->cmap->n, M, nz = a->nz; 2440 const PetscInt *jj; 2441 2442 PetscFunctionBegin; 2443 if (ll) { 2444 /* The local size is used so that VecMPI can be passed to this routine 2445 by MatDiagonalScale_MPIAIJ */ 2446 PetscCall(VecGetLocalSize(ll, &m)); 2447 PetscCheck(m == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Left scaling vector wrong length"); 2448 PetscCall(VecGetArrayRead(ll, &l)); 2449 PetscCall(MatSeqAIJGetArray(A, &v)); 2450 for (i = 0; i < m; i++) { 2451 x = l[i]; 2452 M = a->i[i + 1] - a->i[i]; 2453 for (j = 0; j < M; j++) (*v++) *= x; 2454 } 2455 PetscCall(VecRestoreArrayRead(ll, &l)); 2456 PetscCall(PetscLogFlops(nz)); 2457 PetscCall(MatSeqAIJRestoreArray(A, &v)); 2458 } 2459 if (rr) { 2460 PetscCall(VecGetLocalSize(rr, &n)); 2461 PetscCheck(n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Right scaling vector wrong length"); 2462 PetscCall(VecGetArrayRead(rr, &r)); 2463 PetscCall(MatSeqAIJGetArray(A, &v)); 2464 jj = a->j; 2465 for (i = 0; i < nz; i++) (*v++) *= r[*jj++]; 2466 PetscCall(MatSeqAIJRestoreArray(A, &v)); 2467 PetscCall(VecRestoreArrayRead(rr, &r)); 2468 PetscCall(PetscLogFlops(nz)); 2469 } 2470 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 2471 PetscFunctionReturn(PETSC_SUCCESS); 2472 } 2473 2474 PetscErrorCode MatCreateSubMatrix_SeqAIJ(Mat A, IS isrow, IS iscol, PetscInt csize, MatReuse scall, Mat *B) 2475 { 2476 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *c; 2477 PetscInt *smap, i, k, kstart, kend, oldcols = A->cmap->n, *lens; 2478 PetscInt row, mat_i, *mat_j, tcol, first, step, *mat_ilen, sum, lensi; 2479 const PetscInt *irow, *icol; 2480 const PetscScalar *aa; 2481 PetscInt nrows, ncols; 2482 PetscInt *starts, *j_new, *i_new, *aj = a->j, *ai = a->i, ii, *ailen = a->ilen; 2483 MatScalar *a_new, *mat_a, *c_a; 2484 Mat C; 2485 PetscBool stride; 2486 2487 PetscFunctionBegin; 2488 PetscCall(ISGetIndices(isrow, &irow)); 2489 PetscCall(ISGetLocalSize(isrow, &nrows)); 2490 PetscCall(ISGetLocalSize(iscol, &ncols)); 2491 2492 PetscCall(PetscObjectTypeCompare((PetscObject)iscol, ISSTRIDE, &stride)); 2493 if (stride) { 2494 PetscCall(ISStrideGetInfo(iscol, &first, &step)); 2495 } else { 2496 first = 0; 2497 step = 0; 2498 } 2499 if (stride && step == 1) { 2500 /* special case of contiguous rows */ 2501 PetscCall(PetscMalloc2(nrows, &lens, nrows, &starts)); 2502 /* loop over new rows determining lens and starting points */ 2503 for (i = 0; i < nrows; i++) { 2504 kstart = ai[irow[i]]; 2505 kend = kstart + ailen[irow[i]]; 2506 starts[i] = kstart; 2507 for (k = kstart; k < kend; k++) { 2508 if (aj[k] >= first) { 2509 starts[i] = k; 2510 break; 2511 } 2512 } 2513 sum = 0; 2514 while (k < kend) { 2515 if (aj[k++] >= first + ncols) break; 2516 sum++; 2517 } 2518 lens[i] = sum; 2519 } 2520 /* create submatrix */ 2521 if (scall == MAT_REUSE_MATRIX) { 2522 PetscInt n_cols, n_rows; 2523 PetscCall(MatGetSize(*B, &n_rows, &n_cols)); 2524 PetscCheck(n_rows == nrows && n_cols == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Reused submatrix wrong size"); 2525 PetscCall(MatZeroEntries(*B)); 2526 C = *B; 2527 } else { 2528 PetscInt rbs, cbs; 2529 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 2530 PetscCall(MatSetSizes(C, nrows, ncols, PETSC_DETERMINE, PETSC_DETERMINE)); 2531 PetscCall(ISGetBlockSize(isrow, &rbs)); 2532 PetscCall(ISGetBlockSize(iscol, &cbs)); 2533 PetscCall(MatSetBlockSizes(C, rbs, cbs)); 2534 PetscCall(MatSetType(C, ((PetscObject)A)->type_name)); 2535 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(C, 0, lens)); 2536 } 2537 c = (Mat_SeqAIJ *)C->data; 2538 2539 /* loop over rows inserting into submatrix */ 2540 PetscCall(MatSeqAIJGetArrayWrite(C, &a_new)); // Not 'a_new = c->a-new', since that raw usage ignores offload state of C 2541 j_new = c->j; 2542 i_new = c->i; 2543 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2544 for (i = 0; i < nrows; i++) { 2545 ii = starts[i]; 2546 lensi = lens[i]; 2547 for (k = 0; k < lensi; k++) *j_new++ = aj[ii + k] - first; 2548 PetscCall(PetscArraycpy(a_new, aa + starts[i], lensi)); 2549 a_new += lensi; 2550 i_new[i + 1] = i_new[i] + lensi; 2551 c->ilen[i] = lensi; 2552 } 2553 PetscCall(MatSeqAIJRestoreArrayWrite(C, &a_new)); // Set C's offload state properly 2554 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2555 PetscCall(PetscFree2(lens, starts)); 2556 } else { 2557 PetscCall(ISGetIndices(iscol, &icol)); 2558 PetscCall(PetscCalloc1(oldcols, &smap)); 2559 PetscCall(PetscMalloc1(1 + nrows, &lens)); 2560 for (i = 0; i < ncols; i++) { 2561 PetscCheck(icol[i] < oldcols, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Requesting column beyond largest column icol[%" PetscInt_FMT "] %" PetscInt_FMT " >= A->cmap->n %" PetscInt_FMT, i, icol[i], oldcols); 2562 smap[icol[i]] = i + 1; 2563 } 2564 2565 /* determine lens of each row */ 2566 for (i = 0; i < nrows; i++) { 2567 kstart = ai[irow[i]]; 2568 kend = kstart + a->ilen[irow[i]]; 2569 lens[i] = 0; 2570 for (k = kstart; k < kend; k++) { 2571 if (smap[aj[k]]) lens[i]++; 2572 } 2573 } 2574 /* Create and fill new matrix */ 2575 if (scall == MAT_REUSE_MATRIX) { 2576 PetscBool equal; 2577 2578 c = (Mat_SeqAIJ *)((*B)->data); 2579 PetscCheck((*B)->rmap->n == nrows && (*B)->cmap->n == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Cannot reuse matrix. wrong size"); 2580 PetscCall(PetscArraycmp(c->ilen, lens, (*B)->rmap->n, &equal)); 2581 PetscCheck(equal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Cannot reuse matrix. wrong no of nonzeros"); 2582 PetscCall(PetscArrayzero(c->ilen, (*B)->rmap->n)); 2583 C = *B; 2584 } else { 2585 PetscInt rbs, cbs; 2586 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 2587 PetscCall(MatSetSizes(C, nrows, ncols, PETSC_DETERMINE, PETSC_DETERMINE)); 2588 PetscCall(ISGetBlockSize(isrow, &rbs)); 2589 PetscCall(ISGetBlockSize(iscol, &cbs)); 2590 PetscCall(MatSetBlockSizes(C, rbs, cbs)); 2591 PetscCall(MatSetType(C, ((PetscObject)A)->type_name)); 2592 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(C, 0, lens)); 2593 } 2594 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2595 2596 c = (Mat_SeqAIJ *)(C->data); 2597 PetscCall(MatSeqAIJGetArrayWrite(C, &c_a)); // Not 'c->a', since that raw usage ignores offload state of C 2598 for (i = 0; i < nrows; i++) { 2599 row = irow[i]; 2600 kstart = ai[row]; 2601 kend = kstart + a->ilen[row]; 2602 mat_i = c->i[i]; 2603 mat_j = c->j + mat_i; 2604 mat_a = c_a + mat_i; 2605 mat_ilen = c->ilen + i; 2606 for (k = kstart; k < kend; k++) { 2607 if ((tcol = smap[a->j[k]])) { 2608 *mat_j++ = tcol - 1; 2609 *mat_a++ = aa[k]; 2610 (*mat_ilen)++; 2611 } 2612 } 2613 } 2614 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2615 /* Free work space */ 2616 PetscCall(ISRestoreIndices(iscol, &icol)); 2617 PetscCall(PetscFree(smap)); 2618 PetscCall(PetscFree(lens)); 2619 /* sort */ 2620 for (i = 0; i < nrows; i++) { 2621 PetscInt ilen; 2622 2623 mat_i = c->i[i]; 2624 mat_j = c->j + mat_i; 2625 mat_a = c_a + mat_i; 2626 ilen = c->ilen[i]; 2627 PetscCall(PetscSortIntWithScalarArray(ilen, mat_j, mat_a)); 2628 } 2629 PetscCall(MatSeqAIJRestoreArrayWrite(C, &c_a)); 2630 } 2631 #if defined(PETSC_HAVE_DEVICE) 2632 PetscCall(MatBindToCPU(C, A->boundtocpu)); 2633 #endif 2634 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 2635 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 2636 2637 PetscCall(ISRestoreIndices(isrow, &irow)); 2638 *B = C; 2639 PetscFunctionReturn(PETSC_SUCCESS); 2640 } 2641 2642 PetscErrorCode MatGetMultiProcBlock_SeqAIJ(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat) 2643 { 2644 Mat B; 2645 2646 PetscFunctionBegin; 2647 if (scall == MAT_INITIAL_MATRIX) { 2648 PetscCall(MatCreate(subComm, &B)); 2649 PetscCall(MatSetSizes(B, mat->rmap->n, mat->cmap->n, mat->rmap->n, mat->cmap->n)); 2650 PetscCall(MatSetBlockSizesFromMats(B, mat, mat)); 2651 PetscCall(MatSetType(B, MATSEQAIJ)); 2652 PetscCall(MatDuplicateNoCreate_SeqAIJ(B, mat, MAT_COPY_VALUES, PETSC_TRUE)); 2653 *subMat = B; 2654 } else { 2655 PetscCall(MatCopy_SeqAIJ(mat, *subMat, SAME_NONZERO_PATTERN)); 2656 } 2657 PetscFunctionReturn(PETSC_SUCCESS); 2658 } 2659 2660 PetscErrorCode MatILUFactor_SeqAIJ(Mat inA, IS row, IS col, const MatFactorInfo *info) 2661 { 2662 Mat_SeqAIJ *a = (Mat_SeqAIJ *)inA->data; 2663 Mat outA; 2664 PetscBool row_identity, col_identity; 2665 2666 PetscFunctionBegin; 2667 PetscCheck(info->levels == 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only levels=0 supported for in-place ilu"); 2668 2669 PetscCall(ISIdentity(row, &row_identity)); 2670 PetscCall(ISIdentity(col, &col_identity)); 2671 2672 outA = inA; 2673 outA->factortype = MAT_FACTOR_LU; 2674 PetscCall(PetscFree(inA->solvertype)); 2675 PetscCall(PetscStrallocpy(MATSOLVERPETSC, &inA->solvertype)); 2676 2677 PetscCall(PetscObjectReference((PetscObject)row)); 2678 PetscCall(ISDestroy(&a->row)); 2679 2680 a->row = row; 2681 2682 PetscCall(PetscObjectReference((PetscObject)col)); 2683 PetscCall(ISDestroy(&a->col)); 2684 2685 a->col = col; 2686 2687 /* Create the inverse permutation so that it can be used in MatLUFactorNumeric() */ 2688 PetscCall(ISDestroy(&a->icol)); 2689 PetscCall(ISInvertPermutation(col, PETSC_DECIDE, &a->icol)); 2690 2691 if (!a->solve_work) { /* this matrix may have been factored before */ 2692 PetscCall(PetscMalloc1(inA->rmap->n + 1, &a->solve_work)); 2693 } 2694 2695 PetscCall(MatMarkDiagonal_SeqAIJ(inA)); 2696 if (row_identity && col_identity) { 2697 PetscCall(MatLUFactorNumeric_SeqAIJ_inplace(outA, inA, info)); 2698 } else { 2699 PetscCall(MatLUFactorNumeric_SeqAIJ_InplaceWithPerm(outA, inA, info)); 2700 } 2701 PetscFunctionReturn(PETSC_SUCCESS); 2702 } 2703 2704 PetscErrorCode MatScale_SeqAIJ(Mat inA, PetscScalar alpha) 2705 { 2706 Mat_SeqAIJ *a = (Mat_SeqAIJ *)inA->data; 2707 PetscScalar *v; 2708 PetscBLASInt one = 1, bnz; 2709 2710 PetscFunctionBegin; 2711 PetscCall(MatSeqAIJGetArray(inA, &v)); 2712 PetscCall(PetscBLASIntCast(a->nz, &bnz)); 2713 PetscCallBLAS("BLASscal", BLASscal_(&bnz, &alpha, v, &one)); 2714 PetscCall(PetscLogFlops(a->nz)); 2715 PetscCall(MatSeqAIJRestoreArray(inA, &v)); 2716 PetscCall(MatSeqAIJInvalidateDiagonal(inA)); 2717 PetscFunctionReturn(PETSC_SUCCESS); 2718 } 2719 2720 PetscErrorCode MatDestroySubMatrix_Private(Mat_SubSppt *submatj) 2721 { 2722 PetscInt i; 2723 2724 PetscFunctionBegin; 2725 if (!submatj->id) { /* delete data that are linked only to submats[id=0] */ 2726 PetscCall(PetscFree4(submatj->sbuf1, submatj->ptr, submatj->tmp, submatj->ctr)); 2727 2728 for (i = 0; i < submatj->nrqr; ++i) PetscCall(PetscFree(submatj->sbuf2[i])); 2729 PetscCall(PetscFree3(submatj->sbuf2, submatj->req_size, submatj->req_source1)); 2730 2731 if (submatj->rbuf1) { 2732 PetscCall(PetscFree(submatj->rbuf1[0])); 2733 PetscCall(PetscFree(submatj->rbuf1)); 2734 } 2735 2736 for (i = 0; i < submatj->nrqs; ++i) PetscCall(PetscFree(submatj->rbuf3[i])); 2737 PetscCall(PetscFree3(submatj->req_source2, submatj->rbuf2, submatj->rbuf3)); 2738 PetscCall(PetscFree(submatj->pa)); 2739 } 2740 2741 #if defined(PETSC_USE_CTABLE) 2742 PetscCall(PetscHMapIDestroy(&submatj->rmap)); 2743 if (submatj->cmap_loc) PetscCall(PetscFree(submatj->cmap_loc)); 2744 PetscCall(PetscFree(submatj->rmap_loc)); 2745 #else 2746 PetscCall(PetscFree(submatj->rmap)); 2747 #endif 2748 2749 if (!submatj->allcolumns) { 2750 #if defined(PETSC_USE_CTABLE) 2751 PetscCall(PetscHMapIDestroy((PetscHMapI *)&submatj->cmap)); 2752 #else 2753 PetscCall(PetscFree(submatj->cmap)); 2754 #endif 2755 } 2756 PetscCall(PetscFree(submatj->row2proc)); 2757 2758 PetscCall(PetscFree(submatj)); 2759 PetscFunctionReturn(PETSC_SUCCESS); 2760 } 2761 2762 PetscErrorCode MatDestroySubMatrix_SeqAIJ(Mat C) 2763 { 2764 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data; 2765 Mat_SubSppt *submatj = c->submatis1; 2766 2767 PetscFunctionBegin; 2768 PetscCall((*submatj->destroy)(C)); 2769 PetscCall(MatDestroySubMatrix_Private(submatj)); 2770 PetscFunctionReturn(PETSC_SUCCESS); 2771 } 2772 2773 /* Note this has code duplication with MatDestroySubMatrices_SeqBAIJ() */ 2774 PetscErrorCode MatDestroySubMatrices_SeqAIJ(PetscInt n, Mat *mat[]) 2775 { 2776 PetscInt i; 2777 Mat C; 2778 Mat_SeqAIJ *c; 2779 Mat_SubSppt *submatj; 2780 2781 PetscFunctionBegin; 2782 for (i = 0; i < n; i++) { 2783 C = (*mat)[i]; 2784 c = (Mat_SeqAIJ *)C->data; 2785 submatj = c->submatis1; 2786 if (submatj) { 2787 if (--((PetscObject)C)->refct <= 0) { 2788 PetscCall(PetscFree(C->factorprefix)); 2789 PetscCall((*submatj->destroy)(C)); 2790 PetscCall(MatDestroySubMatrix_Private(submatj)); 2791 PetscCall(PetscFree(C->defaultvectype)); 2792 PetscCall(PetscFree(C->defaultrandtype)); 2793 PetscCall(PetscLayoutDestroy(&C->rmap)); 2794 PetscCall(PetscLayoutDestroy(&C->cmap)); 2795 PetscCall(PetscHeaderDestroy(&C)); 2796 } 2797 } else { 2798 PetscCall(MatDestroy(&C)); 2799 } 2800 } 2801 2802 /* Destroy Dummy submatrices created for reuse */ 2803 PetscCall(MatDestroySubMatrices_Dummy(n, mat)); 2804 2805 PetscCall(PetscFree(*mat)); 2806 PetscFunctionReturn(PETSC_SUCCESS); 2807 } 2808 2809 PetscErrorCode MatCreateSubMatrices_SeqAIJ(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *B[]) 2810 { 2811 PetscInt i; 2812 2813 PetscFunctionBegin; 2814 if (scall == MAT_INITIAL_MATRIX) PetscCall(PetscCalloc1(n + 1, B)); 2815 2816 for (i = 0; i < n; i++) PetscCall(MatCreateSubMatrix_SeqAIJ(A, irow[i], icol[i], PETSC_DECIDE, scall, &(*B)[i])); 2817 PetscFunctionReturn(PETSC_SUCCESS); 2818 } 2819 2820 PetscErrorCode MatIncreaseOverlap_SeqAIJ(Mat A, PetscInt is_max, IS is[], PetscInt ov) 2821 { 2822 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2823 PetscInt row, i, j, k, l, ll, m, n, *nidx, isz, val; 2824 const PetscInt *idx; 2825 PetscInt start, end, *ai, *aj, bs = (A->rmap->bs > 0 && A->rmap->bs == A->cmap->bs) ? A->rmap->bs : 1; 2826 PetscBT table; 2827 2828 PetscFunctionBegin; 2829 m = A->rmap->n / bs; 2830 ai = a->i; 2831 aj = a->j; 2832 2833 PetscCheck(ov >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "illegal negative overlap value used"); 2834 2835 PetscCall(PetscMalloc1(m + 1, &nidx)); 2836 PetscCall(PetscBTCreate(m, &table)); 2837 2838 for (i = 0; i < is_max; i++) { 2839 /* Initialize the two local arrays */ 2840 isz = 0; 2841 PetscCall(PetscBTMemzero(m, table)); 2842 2843 /* Extract the indices, assume there can be duplicate entries */ 2844 PetscCall(ISGetIndices(is[i], &idx)); 2845 PetscCall(ISGetLocalSize(is[i], &n)); 2846 2847 if (bs > 1) { 2848 /* Enter these into the temp arrays. I.e., mark table[row], enter row into new index */ 2849 for (j = 0; j < n; ++j) { 2850 if (!PetscBTLookupSet(table, idx[j] / bs)) nidx[isz++] = idx[j] / bs; 2851 } 2852 PetscCall(ISRestoreIndices(is[i], &idx)); 2853 PetscCall(ISDestroy(&is[i])); 2854 2855 k = 0; 2856 for (j = 0; j < ov; j++) { /* for each overlap */ 2857 n = isz; 2858 for (; k < n; k++) { /* do only those rows in nidx[k], which are not done yet */ 2859 for (ll = 0; ll < bs; ll++) { 2860 row = bs * nidx[k] + ll; 2861 start = ai[row]; 2862 end = ai[row + 1]; 2863 for (l = start; l < end; l++) { 2864 val = aj[l] / bs; 2865 if (!PetscBTLookupSet(table, val)) nidx[isz++] = val; 2866 } 2867 } 2868 } 2869 } 2870 PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, isz, nidx, PETSC_COPY_VALUES, (is + i))); 2871 } else { 2872 /* Enter these into the temp arrays. I.e., mark table[row], enter row into new index */ 2873 for (j = 0; j < n; ++j) { 2874 if (!PetscBTLookupSet(table, idx[j])) nidx[isz++] = idx[j]; 2875 } 2876 PetscCall(ISRestoreIndices(is[i], &idx)); 2877 PetscCall(ISDestroy(&is[i])); 2878 2879 k = 0; 2880 for (j = 0; j < ov; j++) { /* for each overlap */ 2881 n = isz; 2882 for (; k < n; k++) { /* do only those rows in nidx[k], which are not done yet */ 2883 row = nidx[k]; 2884 start = ai[row]; 2885 end = ai[row + 1]; 2886 for (l = start; l < end; l++) { 2887 val = aj[l]; 2888 if (!PetscBTLookupSet(table, val)) nidx[isz++] = val; 2889 } 2890 } 2891 } 2892 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, isz, nidx, PETSC_COPY_VALUES, (is + i))); 2893 } 2894 } 2895 PetscCall(PetscBTDestroy(&table)); 2896 PetscCall(PetscFree(nidx)); 2897 PetscFunctionReturn(PETSC_SUCCESS); 2898 } 2899 2900 /* -------------------------------------------------------------- */ 2901 PetscErrorCode MatPermute_SeqAIJ(Mat A, IS rowp, IS colp, Mat *B) 2902 { 2903 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2904 PetscInt i, nz = 0, m = A->rmap->n, n = A->cmap->n; 2905 const PetscInt *row, *col; 2906 PetscInt *cnew, j, *lens; 2907 IS icolp, irowp; 2908 PetscInt *cwork = NULL; 2909 PetscScalar *vwork = NULL; 2910 2911 PetscFunctionBegin; 2912 PetscCall(ISInvertPermutation(rowp, PETSC_DECIDE, &irowp)); 2913 PetscCall(ISGetIndices(irowp, &row)); 2914 PetscCall(ISInvertPermutation(colp, PETSC_DECIDE, &icolp)); 2915 PetscCall(ISGetIndices(icolp, &col)); 2916 2917 /* determine lengths of permuted rows */ 2918 PetscCall(PetscMalloc1(m + 1, &lens)); 2919 for (i = 0; i < m; i++) lens[row[i]] = a->i[i + 1] - a->i[i]; 2920 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 2921 PetscCall(MatSetSizes(*B, m, n, m, n)); 2922 PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 2923 PetscCall(MatSetType(*B, ((PetscObject)A)->type_name)); 2924 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*B, 0, lens)); 2925 PetscCall(PetscFree(lens)); 2926 2927 PetscCall(PetscMalloc1(n, &cnew)); 2928 for (i = 0; i < m; i++) { 2929 PetscCall(MatGetRow_SeqAIJ(A, i, &nz, &cwork, &vwork)); 2930 for (j = 0; j < nz; j++) cnew[j] = col[cwork[j]]; 2931 PetscCall(MatSetValues_SeqAIJ(*B, 1, &row[i], nz, cnew, vwork, INSERT_VALUES)); 2932 PetscCall(MatRestoreRow_SeqAIJ(A, i, &nz, &cwork, &vwork)); 2933 } 2934 PetscCall(PetscFree(cnew)); 2935 2936 (*B)->assembled = PETSC_FALSE; 2937 2938 #if defined(PETSC_HAVE_DEVICE) 2939 PetscCall(MatBindToCPU(*B, A->boundtocpu)); 2940 #endif 2941 PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 2942 PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 2943 PetscCall(ISRestoreIndices(irowp, &row)); 2944 PetscCall(ISRestoreIndices(icolp, &col)); 2945 PetscCall(ISDestroy(&irowp)); 2946 PetscCall(ISDestroy(&icolp)); 2947 if (rowp == colp) PetscCall(MatPropagateSymmetryOptions(A, *B)); 2948 PetscFunctionReturn(PETSC_SUCCESS); 2949 } 2950 2951 PetscErrorCode MatCopy_SeqAIJ(Mat A, Mat B, MatStructure str) 2952 { 2953 PetscFunctionBegin; 2954 /* If the two matrices have the same copy implementation, use fast copy. */ 2955 if (str == SAME_NONZERO_PATTERN && (A->ops->copy == B->ops->copy)) { 2956 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2957 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 2958 const PetscScalar *aa; 2959 2960 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2961 PetscCheck(a->i[A->rmap->n] == b->i[B->rmap->n], PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of nonzeros in two matrices are different %" PetscInt_FMT " != %" PetscInt_FMT, a->i[A->rmap->n], b->i[B->rmap->n]); 2962 PetscCall(PetscArraycpy(b->a, aa, a->i[A->rmap->n])); 2963 PetscCall(PetscObjectStateIncrease((PetscObject)B)); 2964 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2965 } else { 2966 PetscCall(MatCopy_Basic(A, B, str)); 2967 } 2968 PetscFunctionReturn(PETSC_SUCCESS); 2969 } 2970 2971 PetscErrorCode MatSetUp_SeqAIJ(Mat A) 2972 { 2973 PetscFunctionBegin; 2974 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(A, PETSC_DEFAULT, NULL)); 2975 PetscFunctionReturn(PETSC_SUCCESS); 2976 } 2977 2978 PETSC_INTERN PetscErrorCode MatSeqAIJGetArray_SeqAIJ(Mat A, PetscScalar *array[]) 2979 { 2980 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2981 2982 PetscFunctionBegin; 2983 *array = a->a; 2984 PetscFunctionReturn(PETSC_SUCCESS); 2985 } 2986 2987 PETSC_INTERN PetscErrorCode MatSeqAIJRestoreArray_SeqAIJ(Mat A, PetscScalar *array[]) 2988 { 2989 PetscFunctionBegin; 2990 *array = NULL; 2991 PetscFunctionReturn(PETSC_SUCCESS); 2992 } 2993 2994 /* 2995 Computes the number of nonzeros per row needed for preallocation when X and Y 2996 have different nonzero structure. 2997 */ 2998 PetscErrorCode MatAXPYGetPreallocation_SeqX_private(PetscInt m, const PetscInt *xi, const PetscInt *xj, const PetscInt *yi, const PetscInt *yj, PetscInt *nnz) 2999 { 3000 PetscInt i, j, k, nzx, nzy; 3001 3002 PetscFunctionBegin; 3003 /* Set the number of nonzeros in the new matrix */ 3004 for (i = 0; i < m; i++) { 3005 const PetscInt *xjj = xj + xi[i], *yjj = yj + yi[i]; 3006 nzx = xi[i + 1] - xi[i]; 3007 nzy = yi[i + 1] - yi[i]; 3008 nnz[i] = 0; 3009 for (j = 0, k = 0; j < nzx; j++) { /* Point in X */ 3010 for (; k < nzy && yjj[k] < xjj[j]; k++) nnz[i]++; /* Catch up to X */ 3011 if (k < nzy && yjj[k] == xjj[j]) k++; /* Skip duplicate */ 3012 nnz[i]++; 3013 } 3014 for (; k < nzy; k++) nnz[i]++; 3015 } 3016 PetscFunctionReturn(PETSC_SUCCESS); 3017 } 3018 3019 PetscErrorCode MatAXPYGetPreallocation_SeqAIJ(Mat Y, Mat X, PetscInt *nnz) 3020 { 3021 PetscInt m = Y->rmap->N; 3022 Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data; 3023 Mat_SeqAIJ *y = (Mat_SeqAIJ *)Y->data; 3024 3025 PetscFunctionBegin; 3026 /* Set the number of nonzeros in the new matrix */ 3027 PetscCall(MatAXPYGetPreallocation_SeqX_private(m, x->i, x->j, y->i, y->j, nnz)); 3028 PetscFunctionReturn(PETSC_SUCCESS); 3029 } 3030 3031 PetscErrorCode MatAXPY_SeqAIJ(Mat Y, PetscScalar a, Mat X, MatStructure str) 3032 { 3033 Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data, *y = (Mat_SeqAIJ *)Y->data; 3034 3035 PetscFunctionBegin; 3036 if (str == UNKNOWN_NONZERO_PATTERN || (PetscDefined(USE_DEBUG) && str == SAME_NONZERO_PATTERN)) { 3037 PetscBool e = x->nz == y->nz ? PETSC_TRUE : PETSC_FALSE; 3038 if (e) { 3039 PetscCall(PetscArraycmp(x->i, y->i, Y->rmap->n + 1, &e)); 3040 if (e) { 3041 PetscCall(PetscArraycmp(x->j, y->j, y->nz, &e)); 3042 if (e) str = SAME_NONZERO_PATTERN; 3043 } 3044 } 3045 if (!e) PetscCheck(str != SAME_NONZERO_PATTERN, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatStructure is not SAME_NONZERO_PATTERN"); 3046 } 3047 if (str == SAME_NONZERO_PATTERN) { 3048 const PetscScalar *xa; 3049 PetscScalar *ya, alpha = a; 3050 PetscBLASInt one = 1, bnz; 3051 3052 PetscCall(PetscBLASIntCast(x->nz, &bnz)); 3053 PetscCall(MatSeqAIJGetArray(Y, &ya)); 3054 PetscCall(MatSeqAIJGetArrayRead(X, &xa)); 3055 PetscCallBLAS("BLASaxpy", BLASaxpy_(&bnz, &alpha, xa, &one, ya, &one)); 3056 PetscCall(MatSeqAIJRestoreArrayRead(X, &xa)); 3057 PetscCall(MatSeqAIJRestoreArray(Y, &ya)); 3058 PetscCall(PetscLogFlops(2.0 * bnz)); 3059 PetscCall(MatSeqAIJInvalidateDiagonal(Y)); 3060 PetscCall(PetscObjectStateIncrease((PetscObject)Y)); 3061 } else if (str == SUBSET_NONZERO_PATTERN) { /* nonzeros of X is a subset of Y's */ 3062 PetscCall(MatAXPY_Basic(Y, a, X, str)); 3063 } else { 3064 Mat B; 3065 PetscInt *nnz; 3066 PetscCall(PetscMalloc1(Y->rmap->N, &nnz)); 3067 PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &B)); 3068 PetscCall(PetscObjectSetName((PetscObject)B, ((PetscObject)Y)->name)); 3069 PetscCall(MatSetLayouts(B, Y->rmap, Y->cmap)); 3070 PetscCall(MatSetType(B, ((PetscObject)Y)->type_name)); 3071 PetscCall(MatAXPYGetPreallocation_SeqAIJ(Y, X, nnz)); 3072 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 3073 PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str)); 3074 PetscCall(MatHeaderMerge(Y, &B)); 3075 PetscCall(MatSeqAIJCheckInode(Y)); 3076 PetscCall(PetscFree(nnz)); 3077 } 3078 PetscFunctionReturn(PETSC_SUCCESS); 3079 } 3080 3081 PETSC_INTERN PetscErrorCode MatConjugate_SeqAIJ(Mat mat) 3082 { 3083 #if defined(PETSC_USE_COMPLEX) 3084 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3085 PetscInt i, nz; 3086 PetscScalar *a; 3087 3088 PetscFunctionBegin; 3089 nz = aij->nz; 3090 PetscCall(MatSeqAIJGetArray(mat, &a)); 3091 for (i = 0; i < nz; i++) a[i] = PetscConj(a[i]); 3092 PetscCall(MatSeqAIJRestoreArray(mat, &a)); 3093 #else 3094 PetscFunctionBegin; 3095 #endif 3096 PetscFunctionReturn(PETSC_SUCCESS); 3097 } 3098 3099 PetscErrorCode MatGetRowMaxAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3100 { 3101 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3102 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3103 PetscReal atmp; 3104 PetscScalar *x; 3105 const MatScalar *aa, *av; 3106 3107 PetscFunctionBegin; 3108 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3109 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3110 aa = av; 3111 ai = a->i; 3112 aj = a->j; 3113 3114 PetscCall(VecSet(v, 0.0)); 3115 PetscCall(VecGetArrayWrite(v, &x)); 3116 PetscCall(VecGetLocalSize(v, &n)); 3117 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3118 for (i = 0; i < m; i++) { 3119 ncols = ai[1] - ai[0]; 3120 ai++; 3121 for (j = 0; j < ncols; j++) { 3122 atmp = PetscAbsScalar(*aa); 3123 if (PetscAbsScalar(x[i]) < atmp) { 3124 x[i] = atmp; 3125 if (idx) idx[i] = *aj; 3126 } 3127 aa++; 3128 aj++; 3129 } 3130 } 3131 PetscCall(VecRestoreArrayWrite(v, &x)); 3132 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3133 PetscFunctionReturn(PETSC_SUCCESS); 3134 } 3135 3136 PetscErrorCode MatGetRowMax_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3137 { 3138 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3139 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3140 PetscScalar *x; 3141 const MatScalar *aa, *av; 3142 3143 PetscFunctionBegin; 3144 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3145 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3146 aa = av; 3147 ai = a->i; 3148 aj = a->j; 3149 3150 PetscCall(VecSet(v, 0.0)); 3151 PetscCall(VecGetArrayWrite(v, &x)); 3152 PetscCall(VecGetLocalSize(v, &n)); 3153 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3154 for (i = 0; i < m; i++) { 3155 ncols = ai[1] - ai[0]; 3156 ai++; 3157 if (ncols == A->cmap->n) { /* row is dense */ 3158 x[i] = *aa; 3159 if (idx) idx[i] = 0; 3160 } else { /* row is sparse so already KNOW maximum is 0.0 or higher */ 3161 x[i] = 0.0; 3162 if (idx) { 3163 for (j = 0; j < ncols; j++) { /* find first implicit 0.0 in the row */ 3164 if (aj[j] > j) { 3165 idx[i] = j; 3166 break; 3167 } 3168 } 3169 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3170 if (j == ncols && j < A->cmap->n) idx[i] = j; 3171 } 3172 } 3173 for (j = 0; j < ncols; j++) { 3174 if (PetscRealPart(x[i]) < PetscRealPart(*aa)) { 3175 x[i] = *aa; 3176 if (idx) idx[i] = *aj; 3177 } 3178 aa++; 3179 aj++; 3180 } 3181 } 3182 PetscCall(VecRestoreArrayWrite(v, &x)); 3183 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3184 PetscFunctionReturn(PETSC_SUCCESS); 3185 } 3186 3187 PetscErrorCode MatGetRowMinAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3188 { 3189 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3190 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3191 PetscScalar *x; 3192 const MatScalar *aa, *av; 3193 3194 PetscFunctionBegin; 3195 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3196 aa = av; 3197 ai = a->i; 3198 aj = a->j; 3199 3200 PetscCall(VecSet(v, 0.0)); 3201 PetscCall(VecGetArrayWrite(v, &x)); 3202 PetscCall(VecGetLocalSize(v, &n)); 3203 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector, %" PetscInt_FMT " vs. %" PetscInt_FMT " rows", m, n); 3204 for (i = 0; i < m; i++) { 3205 ncols = ai[1] - ai[0]; 3206 ai++; 3207 if (ncols == A->cmap->n) { /* row is dense */ 3208 x[i] = *aa; 3209 if (idx) idx[i] = 0; 3210 } else { /* row is sparse so already KNOW minimum is 0.0 or higher */ 3211 x[i] = 0.0; 3212 if (idx) { /* find first implicit 0.0 in the row */ 3213 for (j = 0; j < ncols; j++) { 3214 if (aj[j] > j) { 3215 idx[i] = j; 3216 break; 3217 } 3218 } 3219 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3220 if (j == ncols && j < A->cmap->n) idx[i] = j; 3221 } 3222 } 3223 for (j = 0; j < ncols; j++) { 3224 if (PetscAbsScalar(x[i]) > PetscAbsScalar(*aa)) { 3225 x[i] = *aa; 3226 if (idx) idx[i] = *aj; 3227 } 3228 aa++; 3229 aj++; 3230 } 3231 } 3232 PetscCall(VecRestoreArrayWrite(v, &x)); 3233 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3234 PetscFunctionReturn(PETSC_SUCCESS); 3235 } 3236 3237 PetscErrorCode MatGetRowMin_SeqAIJ(Mat A, Vec v, PetscInt idx[]) 3238 { 3239 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3240 PetscInt i, j, m = A->rmap->n, ncols, n; 3241 const PetscInt *ai, *aj; 3242 PetscScalar *x; 3243 const MatScalar *aa, *av; 3244 3245 PetscFunctionBegin; 3246 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3247 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3248 aa = av; 3249 ai = a->i; 3250 aj = a->j; 3251 3252 PetscCall(VecSet(v, 0.0)); 3253 PetscCall(VecGetArrayWrite(v, &x)); 3254 PetscCall(VecGetLocalSize(v, &n)); 3255 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3256 for (i = 0; i < m; i++) { 3257 ncols = ai[1] - ai[0]; 3258 ai++; 3259 if (ncols == A->cmap->n) { /* row is dense */ 3260 x[i] = *aa; 3261 if (idx) idx[i] = 0; 3262 } else { /* row is sparse so already KNOW minimum is 0.0 or lower */ 3263 x[i] = 0.0; 3264 if (idx) { /* find first implicit 0.0 in the row */ 3265 for (j = 0; j < ncols; j++) { 3266 if (aj[j] > j) { 3267 idx[i] = j; 3268 break; 3269 } 3270 } 3271 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3272 if (j == ncols && j < A->cmap->n) idx[i] = j; 3273 } 3274 } 3275 for (j = 0; j < ncols; j++) { 3276 if (PetscRealPart(x[i]) > PetscRealPart(*aa)) { 3277 x[i] = *aa; 3278 if (idx) idx[i] = *aj; 3279 } 3280 aa++; 3281 aj++; 3282 } 3283 } 3284 PetscCall(VecRestoreArrayWrite(v, &x)); 3285 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3286 PetscFunctionReturn(PETSC_SUCCESS); 3287 } 3288 3289 PetscErrorCode MatInvertBlockDiagonal_SeqAIJ(Mat A, const PetscScalar **values) 3290 { 3291 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3292 PetscInt i, bs = PetscAbs(A->rmap->bs), mbs = A->rmap->n / bs, ipvt[5], bs2 = bs * bs, *v_pivots, ij[7], *IJ, j; 3293 MatScalar *diag, work[25], *v_work; 3294 const PetscReal shift = 0.0; 3295 PetscBool allowzeropivot, zeropivotdetected = PETSC_FALSE; 3296 3297 PetscFunctionBegin; 3298 allowzeropivot = PetscNot(A->erroriffailure); 3299 if (a->ibdiagvalid) { 3300 if (values) *values = a->ibdiag; 3301 PetscFunctionReturn(PETSC_SUCCESS); 3302 } 3303 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 3304 if (!a->ibdiag) { PetscCall(PetscMalloc1(bs2 * mbs, &a->ibdiag)); } 3305 diag = a->ibdiag; 3306 if (values) *values = a->ibdiag; 3307 /* factor and invert each block */ 3308 switch (bs) { 3309 case 1: 3310 for (i = 0; i < mbs; i++) { 3311 PetscCall(MatGetValues(A, 1, &i, 1, &i, diag + i)); 3312 if (PetscAbsScalar(diag[i] + shift) < PETSC_MACHINE_EPSILON) { 3313 if (allowzeropivot) { 3314 A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3315 A->factorerror_zeropivot_value = PetscAbsScalar(diag[i]); 3316 A->factorerror_zeropivot_row = i; 3317 PetscCall(PetscInfo(A, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g\n", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON)); 3318 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON); 3319 } 3320 diag[i] = (PetscScalar)1.0 / (diag[i] + shift); 3321 } 3322 break; 3323 case 2: 3324 for (i = 0; i < mbs; i++) { 3325 ij[0] = 2 * i; 3326 ij[1] = 2 * i + 1; 3327 PetscCall(MatGetValues(A, 2, ij, 2, ij, diag)); 3328 PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected)); 3329 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3330 PetscCall(PetscKernel_A_gets_transpose_A_2(diag)); 3331 diag += 4; 3332 } 3333 break; 3334 case 3: 3335 for (i = 0; i < mbs; i++) { 3336 ij[0] = 3 * i; 3337 ij[1] = 3 * i + 1; 3338 ij[2] = 3 * i + 2; 3339 PetscCall(MatGetValues(A, 3, ij, 3, ij, diag)); 3340 PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected)); 3341 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3342 PetscCall(PetscKernel_A_gets_transpose_A_3(diag)); 3343 diag += 9; 3344 } 3345 break; 3346 case 4: 3347 for (i = 0; i < mbs; i++) { 3348 ij[0] = 4 * i; 3349 ij[1] = 4 * i + 1; 3350 ij[2] = 4 * i + 2; 3351 ij[3] = 4 * i + 3; 3352 PetscCall(MatGetValues(A, 4, ij, 4, ij, diag)); 3353 PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected)); 3354 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3355 PetscCall(PetscKernel_A_gets_transpose_A_4(diag)); 3356 diag += 16; 3357 } 3358 break; 3359 case 5: 3360 for (i = 0; i < mbs; i++) { 3361 ij[0] = 5 * i; 3362 ij[1] = 5 * i + 1; 3363 ij[2] = 5 * i + 2; 3364 ij[3] = 5 * i + 3; 3365 ij[4] = 5 * i + 4; 3366 PetscCall(MatGetValues(A, 5, ij, 5, ij, diag)); 3367 PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected)); 3368 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3369 PetscCall(PetscKernel_A_gets_transpose_A_5(diag)); 3370 diag += 25; 3371 } 3372 break; 3373 case 6: 3374 for (i = 0; i < mbs; i++) { 3375 ij[0] = 6 * i; 3376 ij[1] = 6 * i + 1; 3377 ij[2] = 6 * i + 2; 3378 ij[3] = 6 * i + 3; 3379 ij[4] = 6 * i + 4; 3380 ij[5] = 6 * i + 5; 3381 PetscCall(MatGetValues(A, 6, ij, 6, ij, diag)); 3382 PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected)); 3383 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3384 PetscCall(PetscKernel_A_gets_transpose_A_6(diag)); 3385 diag += 36; 3386 } 3387 break; 3388 case 7: 3389 for (i = 0; i < mbs; i++) { 3390 ij[0] = 7 * i; 3391 ij[1] = 7 * i + 1; 3392 ij[2] = 7 * i + 2; 3393 ij[3] = 7 * i + 3; 3394 ij[4] = 7 * i + 4; 3395 ij[5] = 7 * i + 5; 3396 ij[6] = 7 * i + 6; 3397 PetscCall(MatGetValues(A, 7, ij, 7, ij, diag)); 3398 PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected)); 3399 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3400 PetscCall(PetscKernel_A_gets_transpose_A_7(diag)); 3401 diag += 49; 3402 } 3403 break; 3404 default: 3405 PetscCall(PetscMalloc3(bs, &v_work, bs, &v_pivots, bs, &IJ)); 3406 for (i = 0; i < mbs; i++) { 3407 for (j = 0; j < bs; j++) IJ[j] = bs * i + j; 3408 PetscCall(MatGetValues(A, bs, IJ, bs, IJ, diag)); 3409 PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected)); 3410 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3411 PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bs)); 3412 diag += bs2; 3413 } 3414 PetscCall(PetscFree3(v_work, v_pivots, IJ)); 3415 } 3416 a->ibdiagvalid = PETSC_TRUE; 3417 PetscFunctionReturn(PETSC_SUCCESS); 3418 } 3419 3420 static PetscErrorCode MatSetRandom_SeqAIJ(Mat x, PetscRandom rctx) 3421 { 3422 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3423 PetscScalar a, *aa; 3424 PetscInt m, n, i, j, col; 3425 3426 PetscFunctionBegin; 3427 if (!x->assembled) { 3428 PetscCall(MatGetSize(x, &m, &n)); 3429 for (i = 0; i < m; i++) { 3430 for (j = 0; j < aij->imax[i]; j++) { 3431 PetscCall(PetscRandomGetValue(rctx, &a)); 3432 col = (PetscInt)(n * PetscRealPart(a)); 3433 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3434 } 3435 } 3436 } else { 3437 PetscCall(MatSeqAIJGetArrayWrite(x, &aa)); 3438 for (i = 0; i < aij->nz; i++) PetscCall(PetscRandomGetValue(rctx, aa + i)); 3439 PetscCall(MatSeqAIJRestoreArrayWrite(x, &aa)); 3440 } 3441 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3442 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3443 PetscFunctionReturn(PETSC_SUCCESS); 3444 } 3445 3446 /* Like MatSetRandom_SeqAIJ, but do not set values on columns in range of [low, high) */ 3447 PetscErrorCode MatSetRandomSkipColumnRange_SeqAIJ_Private(Mat x, PetscInt low, PetscInt high, PetscRandom rctx) 3448 { 3449 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3450 PetscScalar a; 3451 PetscInt m, n, i, j, col, nskip; 3452 3453 PetscFunctionBegin; 3454 nskip = high - low; 3455 PetscCall(MatGetSize(x, &m, &n)); 3456 n -= nskip; /* shrink number of columns where nonzeros can be set */ 3457 for (i = 0; i < m; i++) { 3458 for (j = 0; j < aij->imax[i]; j++) { 3459 PetscCall(PetscRandomGetValue(rctx, &a)); 3460 col = (PetscInt)(n * PetscRealPart(a)); 3461 if (col >= low) col += nskip; /* shift col rightward to skip the hole */ 3462 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3463 } 3464 } 3465 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3466 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3467 PetscFunctionReturn(PETSC_SUCCESS); 3468 } 3469 3470 /* -------------------------------------------------------------------*/ 3471 static struct _MatOps MatOps_Values = {MatSetValues_SeqAIJ, 3472 MatGetRow_SeqAIJ, 3473 MatRestoreRow_SeqAIJ, 3474 MatMult_SeqAIJ, 3475 /* 4*/ MatMultAdd_SeqAIJ, 3476 MatMultTranspose_SeqAIJ, 3477 MatMultTransposeAdd_SeqAIJ, 3478 NULL, 3479 NULL, 3480 NULL, 3481 /* 10*/ NULL, 3482 MatLUFactor_SeqAIJ, 3483 NULL, 3484 MatSOR_SeqAIJ, 3485 MatTranspose_SeqAIJ, 3486 /*1 5*/ MatGetInfo_SeqAIJ, 3487 MatEqual_SeqAIJ, 3488 MatGetDiagonal_SeqAIJ, 3489 MatDiagonalScale_SeqAIJ, 3490 MatNorm_SeqAIJ, 3491 /* 20*/ NULL, 3492 MatAssemblyEnd_SeqAIJ, 3493 MatSetOption_SeqAIJ, 3494 MatZeroEntries_SeqAIJ, 3495 /* 24*/ MatZeroRows_SeqAIJ, 3496 NULL, 3497 NULL, 3498 NULL, 3499 NULL, 3500 /* 29*/ MatSetUp_SeqAIJ, 3501 NULL, 3502 NULL, 3503 NULL, 3504 NULL, 3505 /* 34*/ MatDuplicate_SeqAIJ, 3506 NULL, 3507 NULL, 3508 MatILUFactor_SeqAIJ, 3509 NULL, 3510 /* 39*/ MatAXPY_SeqAIJ, 3511 MatCreateSubMatrices_SeqAIJ, 3512 MatIncreaseOverlap_SeqAIJ, 3513 MatGetValues_SeqAIJ, 3514 MatCopy_SeqAIJ, 3515 /* 44*/ MatGetRowMax_SeqAIJ, 3516 MatScale_SeqAIJ, 3517 MatShift_SeqAIJ, 3518 MatDiagonalSet_SeqAIJ, 3519 MatZeroRowsColumns_SeqAIJ, 3520 /* 49*/ MatSetRandom_SeqAIJ, 3521 MatGetRowIJ_SeqAIJ, 3522 MatRestoreRowIJ_SeqAIJ, 3523 MatGetColumnIJ_SeqAIJ, 3524 MatRestoreColumnIJ_SeqAIJ, 3525 /* 54*/ MatFDColoringCreate_SeqXAIJ, 3526 NULL, 3527 NULL, 3528 MatPermute_SeqAIJ, 3529 NULL, 3530 /* 59*/ NULL, 3531 MatDestroy_SeqAIJ, 3532 MatView_SeqAIJ, 3533 NULL, 3534 NULL, 3535 /* 64*/ NULL, 3536 MatMatMatMultNumeric_SeqAIJ_SeqAIJ_SeqAIJ, 3537 NULL, 3538 NULL, 3539 NULL, 3540 /* 69*/ MatGetRowMaxAbs_SeqAIJ, 3541 MatGetRowMinAbs_SeqAIJ, 3542 NULL, 3543 NULL, 3544 NULL, 3545 /* 74*/ NULL, 3546 MatFDColoringApply_AIJ, 3547 NULL, 3548 NULL, 3549 NULL, 3550 /* 79*/ MatFindZeroDiagonals_SeqAIJ, 3551 NULL, 3552 NULL, 3553 NULL, 3554 MatLoad_SeqAIJ, 3555 /* 84*/ MatIsSymmetric_SeqAIJ, 3556 MatIsHermitian_SeqAIJ, 3557 NULL, 3558 NULL, 3559 NULL, 3560 /* 89*/ NULL, 3561 NULL, 3562 MatMatMultNumeric_SeqAIJ_SeqAIJ, 3563 NULL, 3564 NULL, 3565 /* 94*/ MatPtAPNumeric_SeqAIJ_SeqAIJ_SparseAxpy, 3566 NULL, 3567 NULL, 3568 MatMatTransposeMultNumeric_SeqAIJ_SeqAIJ, 3569 NULL, 3570 /* 99*/ MatProductSetFromOptions_SeqAIJ, 3571 NULL, 3572 NULL, 3573 MatConjugate_SeqAIJ, 3574 NULL, 3575 /*104*/ MatSetValuesRow_SeqAIJ, 3576 MatRealPart_SeqAIJ, 3577 MatImaginaryPart_SeqAIJ, 3578 NULL, 3579 NULL, 3580 /*109*/ MatMatSolve_SeqAIJ, 3581 NULL, 3582 MatGetRowMin_SeqAIJ, 3583 NULL, 3584 MatMissingDiagonal_SeqAIJ, 3585 /*114*/ NULL, 3586 NULL, 3587 NULL, 3588 NULL, 3589 NULL, 3590 /*119*/ NULL, 3591 NULL, 3592 NULL, 3593 NULL, 3594 MatGetMultiProcBlock_SeqAIJ, 3595 /*124*/ MatFindNonzeroRows_SeqAIJ, 3596 MatGetColumnReductions_SeqAIJ, 3597 MatInvertBlockDiagonal_SeqAIJ, 3598 MatInvertVariableBlockDiagonal_SeqAIJ, 3599 NULL, 3600 /*129*/ NULL, 3601 NULL, 3602 NULL, 3603 MatTransposeMatMultNumeric_SeqAIJ_SeqAIJ, 3604 MatTransposeColoringCreate_SeqAIJ, 3605 /*134*/ MatTransColoringApplySpToDen_SeqAIJ, 3606 MatTransColoringApplyDenToSp_SeqAIJ, 3607 NULL, 3608 NULL, 3609 MatRARtNumeric_SeqAIJ_SeqAIJ, 3610 /*139*/ NULL, 3611 NULL, 3612 NULL, 3613 MatFDColoringSetUp_SeqXAIJ, 3614 MatFindOffBlockDiagonalEntries_SeqAIJ, 3615 MatCreateMPIMatConcatenateSeqMat_SeqAIJ, 3616 /*145*/ MatDestroySubMatrices_SeqAIJ, 3617 NULL, 3618 NULL, 3619 MatCreateGraph_Simple_AIJ, 3620 NULL, 3621 /*150*/ MatTransposeSymbolic_SeqAIJ, 3622 MatEliminateZeros_SeqAIJ}; 3623 3624 PetscErrorCode MatSeqAIJSetColumnIndices_SeqAIJ(Mat mat, PetscInt *indices) 3625 { 3626 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3627 PetscInt i, nz, n; 3628 3629 PetscFunctionBegin; 3630 nz = aij->maxnz; 3631 n = mat->rmap->n; 3632 for (i = 0; i < nz; i++) aij->j[i] = indices[i]; 3633 aij->nz = nz; 3634 for (i = 0; i < n; i++) aij->ilen[i] = aij->imax[i]; 3635 PetscFunctionReturn(PETSC_SUCCESS); 3636 } 3637 3638 /* 3639 * Given a sparse matrix with global column indices, compact it by using a local column space. 3640 * The result matrix helps saving memory in other algorithms, such as MatPtAPSymbolic_MPIAIJ_MPIAIJ_scalable() 3641 */ 3642 PetscErrorCode MatSeqAIJCompactOutExtraColumns_SeqAIJ(Mat mat, ISLocalToGlobalMapping *mapping) 3643 { 3644 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3645 PetscHMapI gid1_lid1; 3646 PetscHashIter tpos; 3647 PetscInt gid, lid, i, ec, nz = aij->nz; 3648 PetscInt *garray, *jj = aij->j; 3649 3650 PetscFunctionBegin; 3651 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3652 PetscValidPointer(mapping, 2); 3653 /* use a table */ 3654 PetscCall(PetscHMapICreateWithSize(mat->rmap->n, &gid1_lid1)); 3655 ec = 0; 3656 for (i = 0; i < nz; i++) { 3657 PetscInt data, gid1 = jj[i] + 1; 3658 PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &data)); 3659 if (!data) { 3660 /* one based table */ 3661 PetscCall(PetscHMapISet(gid1_lid1, gid1, ++ec)); 3662 } 3663 } 3664 /* form array of columns we need */ 3665 PetscCall(PetscMalloc1(ec, &garray)); 3666 PetscHashIterBegin(gid1_lid1, tpos); 3667 while (!PetscHashIterAtEnd(gid1_lid1, tpos)) { 3668 PetscHashIterGetKey(gid1_lid1, tpos, gid); 3669 PetscHashIterGetVal(gid1_lid1, tpos, lid); 3670 PetscHashIterNext(gid1_lid1, tpos); 3671 gid--; 3672 lid--; 3673 garray[lid] = gid; 3674 } 3675 PetscCall(PetscSortInt(ec, garray)); /* sort, and rebuild */ 3676 PetscCall(PetscHMapIClear(gid1_lid1)); 3677 for (i = 0; i < ec; i++) PetscCall(PetscHMapISet(gid1_lid1, garray[i] + 1, i + 1)); 3678 /* compact out the extra columns in B */ 3679 for (i = 0; i < nz; i++) { 3680 PetscInt gid1 = jj[i] + 1; 3681 PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &lid)); 3682 lid--; 3683 jj[i] = lid; 3684 } 3685 PetscCall(PetscLayoutDestroy(&mat->cmap)); 3686 PetscCall(PetscHMapIDestroy(&gid1_lid1)); 3687 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)mat), ec, ec, 1, &mat->cmap)); 3688 PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, mat->cmap->bs, mat->cmap->n, garray, PETSC_OWN_POINTER, mapping)); 3689 PetscCall(ISLocalToGlobalMappingSetType(*mapping, ISLOCALTOGLOBALMAPPINGHASH)); 3690 PetscFunctionReturn(PETSC_SUCCESS); 3691 } 3692 3693 /*@ 3694 MatSeqAIJSetColumnIndices - Set the column indices for all the rows 3695 in the matrix. 3696 3697 Input Parameters: 3698 + mat - the `MATSEQAIJ` matrix 3699 - indices - the column indices 3700 3701 Level: advanced 3702 3703 Notes: 3704 This can be called if you have precomputed the nonzero structure of the 3705 matrix and want to provide it to the matrix object to improve the performance 3706 of the `MatSetValues()` operation. 3707 3708 You MUST have set the correct numbers of nonzeros per row in the call to 3709 `MatCreateSeqAIJ()`, and the columns indices MUST be sorted. 3710 3711 MUST be called before any calls to `MatSetValues()` 3712 3713 The indices should start with zero, not one. 3714 3715 @*/ 3716 PetscErrorCode MatSeqAIJSetColumnIndices(Mat mat, PetscInt *indices) 3717 { 3718 PetscFunctionBegin; 3719 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3720 PetscValidIntPointer(indices, 2); 3721 PetscUseMethod(mat, "MatSeqAIJSetColumnIndices_C", (Mat, PetscInt *), (mat, indices)); 3722 PetscFunctionReturn(PETSC_SUCCESS); 3723 } 3724 3725 /* ----------------------------------------------------------------------------------------*/ 3726 3727 PetscErrorCode MatStoreValues_SeqAIJ(Mat mat) 3728 { 3729 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3730 size_t nz = aij->i[mat->rmap->n]; 3731 3732 PetscFunctionBegin; 3733 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3734 3735 /* allocate space for values if not already there */ 3736 if (!aij->saved_values) { PetscCall(PetscMalloc1(nz + 1, &aij->saved_values)); } 3737 3738 /* copy values over */ 3739 PetscCall(PetscArraycpy(aij->saved_values, aij->a, nz)); 3740 PetscFunctionReturn(PETSC_SUCCESS); 3741 } 3742 3743 /*@ 3744 MatStoreValues - Stashes a copy of the matrix values; this allows, for 3745 example, reuse of the linear part of a Jacobian, while recomputing the 3746 nonlinear portion. 3747 3748 Logically Collect 3749 3750 Input Parameters: 3751 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3752 3753 Level: advanced 3754 3755 Common Usage, with `SNESSolve()`: 3756 $ Create Jacobian matrix 3757 $ Set linear terms into matrix 3758 $ Apply boundary conditions to matrix, at this time matrix must have 3759 $ final nonzero structure (i.e. setting the nonlinear terms and applying 3760 $ boundary conditions again will not change the nonzero structure 3761 $ ierr = MatSetOption(mat,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE); 3762 $ ierr = MatStoreValues(mat); 3763 $ Call SNESSetJacobian() with matrix 3764 $ In your Jacobian routine 3765 $ ierr = MatRetrieveValues(mat); 3766 $ Set nonlinear terms in matrix 3767 3768 Common Usage without SNESSolve(), i.e. when you handle nonlinear solve yourself: 3769 $ // build linear portion of Jacobian 3770 $ ierr = MatSetOption(mat,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE); 3771 $ ierr = MatStoreValues(mat); 3772 $ loop over nonlinear iterations 3773 $ ierr = MatRetrieveValues(mat); 3774 $ // call MatSetValues(mat,...) to set nonliner portion of Jacobian 3775 $ // call MatAssemblyBegin/End() on matrix 3776 $ Solve linear system with Jacobian 3777 $ endloop 3778 3779 Notes: 3780 Matrix must already be assembled before calling this routine 3781 Must set the matrix option `MatSetOption`(mat,`MAT_NEW_NONZERO_LOCATIONS`,`PETSC_FALSE`); before 3782 calling this routine. 3783 3784 When this is called multiple times it overwrites the previous set of stored values 3785 and does not allocated additional space. 3786 3787 .seealso: `MatRetrieveValues()` 3788 @*/ 3789 PetscErrorCode MatStoreValues(Mat mat) 3790 { 3791 PetscFunctionBegin; 3792 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3793 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3794 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3795 PetscUseMethod(mat, "MatStoreValues_C", (Mat), (mat)); 3796 PetscFunctionReturn(PETSC_SUCCESS); 3797 } 3798 3799 PetscErrorCode MatRetrieveValues_SeqAIJ(Mat mat) 3800 { 3801 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3802 PetscInt nz = aij->i[mat->rmap->n]; 3803 3804 PetscFunctionBegin; 3805 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3806 PetscCheck(aij->saved_values, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatStoreValues(A);first"); 3807 /* copy values over */ 3808 PetscCall(PetscArraycpy(aij->a, aij->saved_values, nz)); 3809 PetscFunctionReturn(PETSC_SUCCESS); 3810 } 3811 3812 /*@ 3813 MatRetrieveValues - Retrieves the copy of the matrix values; this allows, for 3814 example, reuse of the linear part of a Jacobian, while recomputing the 3815 nonlinear portion. 3816 3817 Logically Collect 3818 3819 Input Parameters: 3820 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3821 3822 Level: advanced 3823 3824 .seealso: `MatStoreValues()` 3825 @*/ 3826 PetscErrorCode MatRetrieveValues(Mat mat) 3827 { 3828 PetscFunctionBegin; 3829 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3830 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3831 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3832 PetscUseMethod(mat, "MatRetrieveValues_C", (Mat), (mat)); 3833 PetscFunctionReturn(PETSC_SUCCESS); 3834 } 3835 3836 /* --------------------------------------------------------------------------------*/ 3837 /*@C 3838 MatCreateSeqAIJ - Creates a sparse matrix in `MATSEQAIJ` (compressed row) format 3839 (the default parallel PETSc format). For good matrix assembly performance 3840 the user should preallocate the matrix storage by setting the parameter nz 3841 (or the array nnz). By setting these parameters accurately, performance 3842 during matrix assembly can be increased by more than a factor of 50. 3843 3844 Collective 3845 3846 Input Parameters: 3847 + comm - MPI communicator, set to `PETSC_COMM_SELF` 3848 . m - number of rows 3849 . n - number of columns 3850 . nz - number of nonzeros per row (same for all rows) 3851 - nnz - array containing the number of nonzeros in the various rows 3852 (possibly different for each row) or NULL 3853 3854 Output Parameter: 3855 . A - the matrix 3856 3857 It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`, 3858 MatXXXXSetPreallocation() paradigm instead of this routine directly. 3859 [MatXXXXSetPreallocation() is, for example, `MatSeqAIJSetPreallocation()`] 3860 3861 Notes: 3862 If nnz is given then nz is ignored 3863 3864 The AIJ format, also called 3865 compressed row storage, is fully compatible with standard Fortran 77 3866 storage. That is, the stored row and column indices can begin at 3867 either one (as in Fortran) or zero. See the users' manual for details. 3868 3869 Specify the preallocated storage with either nz or nnz (not both). 3870 Set nz = `PETSC_DEFAULT` and nnz = NULL for PETSc to control dynamic memory 3871 allocation. For large problems you MUST preallocate memory or you 3872 will get TERRIBLE performance, see the users' manual chapter on matrices. 3873 3874 By default, this format uses inodes (identical nodes) when possible, to 3875 improve numerical efficiency of matrix-vector products and solves. We 3876 search for consecutive rows with the same nonzero structure, thereby 3877 reusing matrix information to achieve increased efficiency. 3878 3879 Options Database Keys: 3880 + -mat_no_inode - Do not use inodes 3881 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3882 3883 Level: intermediate 3884 3885 .seealso: [Sparse Matrix Creation](sec_matsparse), `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()` 3886 @*/ 3887 PetscErrorCode MatCreateSeqAIJ(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt nz, const PetscInt nnz[], Mat *A) 3888 { 3889 PetscFunctionBegin; 3890 PetscCall(MatCreate(comm, A)); 3891 PetscCall(MatSetSizes(*A, m, n, m, n)); 3892 PetscCall(MatSetType(*A, MATSEQAIJ)); 3893 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*A, nz, nnz)); 3894 PetscFunctionReturn(PETSC_SUCCESS); 3895 } 3896 3897 /*@C 3898 MatSeqAIJSetPreallocation - For good matrix assembly performance 3899 the user should preallocate the matrix storage by setting the parameter nz 3900 (or the array nnz). By setting these parameters accurately, performance 3901 during matrix assembly can be increased by more than a factor of 50. 3902 3903 Collective 3904 3905 Input Parameters: 3906 + B - The matrix 3907 . nz - number of nonzeros per row (same for all rows) 3908 - nnz - array containing the number of nonzeros in the various rows 3909 (possibly different for each row) or NULL 3910 3911 Notes: 3912 If nnz is given then nz is ignored 3913 3914 The `MATSEQAIJ` format also called 3915 compressed row storage, is fully compatible with standard Fortran 77 3916 storage. That is, the stored row and column indices can begin at 3917 either one (as in Fortran) or zero. See the users' manual for details. 3918 3919 Specify the preallocated storage with either nz or nnz (not both). 3920 Set nz = `PETSC_DEFAULT` and nnz = NULL for PETSc to control dynamic memory 3921 allocation. For large problems you MUST preallocate memory or you 3922 will get TERRIBLE performance, see the users' manual chapter on matrices. 3923 3924 You can call `MatGetInfo()` to get information on how effective the preallocation was; 3925 for example the fields mallocs,nz_allocated,nz_used,nz_unneeded; 3926 You can also run with the option -info and look for messages with the string 3927 malloc in them to see if additional memory allocation was needed. 3928 3929 Developer Notes: 3930 Use nz of `MAT_SKIP_ALLOCATION` to not allocate any space for the matrix 3931 entries or columns indices 3932 3933 By default, this format uses inodes (identical nodes) when possible, to 3934 improve numerical efficiency of matrix-vector products and solves. We 3935 search for consecutive rows with the same nonzero structure, thereby 3936 reusing matrix information to achieve increased efficiency. 3937 3938 Options Database Keys: 3939 + -mat_no_inode - Do not use inodes 3940 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3941 3942 Level: intermediate 3943 3944 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()`, `MatGetInfo()`, 3945 `MatSeqAIJSetTotalPreallocation()` 3946 @*/ 3947 PetscErrorCode MatSeqAIJSetPreallocation(Mat B, PetscInt nz, const PetscInt nnz[]) 3948 { 3949 PetscFunctionBegin; 3950 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 3951 PetscValidType(B, 1); 3952 PetscTryMethod(B, "MatSeqAIJSetPreallocation_C", (Mat, PetscInt, const PetscInt[]), (B, nz, nnz)); 3953 PetscFunctionReturn(PETSC_SUCCESS); 3954 } 3955 3956 PetscErrorCode MatSeqAIJSetPreallocation_SeqAIJ(Mat B, PetscInt nz, const PetscInt *nnz) 3957 { 3958 Mat_SeqAIJ *b; 3959 PetscBool skipallocation = PETSC_FALSE, realalloc = PETSC_FALSE; 3960 PetscInt i; 3961 3962 PetscFunctionBegin; 3963 if (nz >= 0 || nnz) realalloc = PETSC_TRUE; 3964 if (nz == MAT_SKIP_ALLOCATION) { 3965 skipallocation = PETSC_TRUE; 3966 nz = 0; 3967 } 3968 PetscCall(PetscLayoutSetUp(B->rmap)); 3969 PetscCall(PetscLayoutSetUp(B->cmap)); 3970 3971 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5; 3972 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nz cannot be less than 0: value %" PetscInt_FMT, nz); 3973 if (PetscUnlikelyDebug(nnz)) { 3974 for (i = 0; i < B->rmap->n; i++) { 3975 PetscCheck(nnz[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nnz cannot be less than 0: local row %" PetscInt_FMT " value %" PetscInt_FMT, i, nnz[i]); 3976 PetscCheck(nnz[i] <= B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nnz cannot be greater than row length: local row %" PetscInt_FMT " value %" PetscInt_FMT " rowlength %" PetscInt_FMT, i, nnz[i], B->cmap->n); 3977 } 3978 } 3979 3980 B->preallocated = PETSC_TRUE; 3981 3982 b = (Mat_SeqAIJ *)B->data; 3983 3984 if (!skipallocation) { 3985 if (!b->imax) { PetscCall(PetscMalloc1(B->rmap->n, &b->imax)); } 3986 if (!b->ilen) { 3987 /* b->ilen will count nonzeros in each row so far. */ 3988 PetscCall(PetscCalloc1(B->rmap->n, &b->ilen)); 3989 } else { 3990 PetscCall(PetscMemzero(b->ilen, B->rmap->n * sizeof(PetscInt))); 3991 } 3992 if (!b->ipre) { PetscCall(PetscMalloc1(B->rmap->n, &b->ipre)); } 3993 if (!nnz) { 3994 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 10; 3995 else if (nz < 0) nz = 1; 3996 nz = PetscMin(nz, B->cmap->n); 3997 for (i = 0; i < B->rmap->n; i++) b->imax[i] = nz; 3998 nz = nz * B->rmap->n; 3999 } else { 4000 PetscInt64 nz64 = 0; 4001 for (i = 0; i < B->rmap->n; i++) { 4002 b->imax[i] = nnz[i]; 4003 nz64 += nnz[i]; 4004 } 4005 PetscCall(PetscIntCast(nz64, &nz)); 4006 } 4007 4008 /* allocate the matrix space */ 4009 /* FIXME: should B's old memory be unlogged? */ 4010 PetscCall(MatSeqXAIJFreeAIJ(B, &b->a, &b->j, &b->i)); 4011 if (B->structure_only) { 4012 PetscCall(PetscMalloc1(nz, &b->j)); 4013 PetscCall(PetscMalloc1(B->rmap->n + 1, &b->i)); 4014 } else { 4015 PetscCall(PetscMalloc3(nz, &b->a, nz, &b->j, B->rmap->n + 1, &b->i)); 4016 } 4017 b->i[0] = 0; 4018 for (i = 1; i < B->rmap->n + 1; i++) b->i[i] = b->i[i - 1] + b->imax[i - 1]; 4019 if (B->structure_only) { 4020 b->singlemalloc = PETSC_FALSE; 4021 b->free_a = PETSC_FALSE; 4022 } else { 4023 b->singlemalloc = PETSC_TRUE; 4024 b->free_a = PETSC_TRUE; 4025 } 4026 b->free_ij = PETSC_TRUE; 4027 } else { 4028 b->free_a = PETSC_FALSE; 4029 b->free_ij = PETSC_FALSE; 4030 } 4031 4032 if (b->ipre && nnz != b->ipre && b->imax) { 4033 /* reserve user-requested sparsity */ 4034 PetscCall(PetscArraycpy(b->ipre, b->imax, B->rmap->n)); 4035 } 4036 4037 b->nz = 0; 4038 b->maxnz = nz; 4039 B->info.nz_unneeded = (double)b->maxnz; 4040 if (realalloc) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 4041 B->was_assembled = PETSC_FALSE; 4042 B->assembled = PETSC_FALSE; 4043 /* We simply deem preallocation has changed nonzero state. Updating the state 4044 will give clients (like AIJKokkos) a chance to know something has happened. 4045 */ 4046 B->nonzerostate++; 4047 PetscFunctionReturn(PETSC_SUCCESS); 4048 } 4049 4050 PetscErrorCode MatResetPreallocation_SeqAIJ(Mat A) 4051 { 4052 Mat_SeqAIJ *a; 4053 PetscInt i; 4054 4055 PetscFunctionBegin; 4056 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4057 4058 /* Check local size. If zero, then return */ 4059 if (!A->rmap->n) PetscFunctionReturn(PETSC_SUCCESS); 4060 4061 a = (Mat_SeqAIJ *)A->data; 4062 /* if no saved info, we error out */ 4063 PetscCheck(a->ipre, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "No saved preallocation info "); 4064 4065 PetscCheck(a->i && a->j && a->a && a->imax && a->ilen, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Memory info is incomplete, and can not reset preallocation "); 4066 4067 PetscCall(PetscArraycpy(a->imax, a->ipre, A->rmap->n)); 4068 PetscCall(PetscArrayzero(a->ilen, A->rmap->n)); 4069 a->i[0] = 0; 4070 for (i = 1; i < A->rmap->n + 1; i++) a->i[i] = a->i[i - 1] + a->imax[i - 1]; 4071 A->preallocated = PETSC_TRUE; 4072 a->nz = 0; 4073 a->maxnz = a->i[A->rmap->n]; 4074 A->info.nz_unneeded = (double)a->maxnz; 4075 A->was_assembled = PETSC_FALSE; 4076 A->assembled = PETSC_FALSE; 4077 PetscFunctionReturn(PETSC_SUCCESS); 4078 } 4079 4080 /*@ 4081 MatSeqAIJSetPreallocationCSR - Allocates memory for a sparse sequential matrix in `MATSEQAIJ` format. 4082 4083 Input Parameters: 4084 + B - the matrix 4085 . i - the indices into j for the start of each row (starts with zero) 4086 . j - the column indices for each row (starts with zero) these must be sorted for each row 4087 - v - optional values in the matrix 4088 4089 Level: developer 4090 4091 Notes: 4092 The i,j,v values are COPIED with this routine; to avoid the copy use `MatCreateSeqAIJWithArrays()` 4093 4094 This routine may be called multiple times with different nonzero patterns (or the same nonzero pattern). The nonzero 4095 structure will be the union of all the previous nonzero structures. 4096 4097 Developer Notes: 4098 An optimization could be added to the implementation where it checks if the i, and j are identical to the current i and j and 4099 then just copies the v values directly with `PetscMemcpy()`. 4100 4101 This routine could also take a `PetscCopyMode` argument to allow sharing the values instead of always copying them. 4102 4103 .seealso: `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatSeqAIJSetPreallocation()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MatResetPreallocation()` 4104 @*/ 4105 PetscErrorCode MatSeqAIJSetPreallocationCSR(Mat B, const PetscInt i[], const PetscInt j[], const PetscScalar v[]) 4106 { 4107 PetscFunctionBegin; 4108 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 4109 PetscValidType(B, 1); 4110 PetscTryMethod(B, "MatSeqAIJSetPreallocationCSR_C", (Mat, const PetscInt[], const PetscInt[], const PetscScalar[]), (B, i, j, v)); 4111 PetscFunctionReturn(PETSC_SUCCESS); 4112 } 4113 4114 PetscErrorCode MatSeqAIJSetPreallocationCSR_SeqAIJ(Mat B, const PetscInt Ii[], const PetscInt J[], const PetscScalar v[]) 4115 { 4116 PetscInt i; 4117 PetscInt m, n; 4118 PetscInt nz; 4119 PetscInt *nnz; 4120 4121 PetscFunctionBegin; 4122 PetscCheck(Ii[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Ii[0] must be 0 it is %" PetscInt_FMT, Ii[0]); 4123 4124 PetscCall(PetscLayoutSetUp(B->rmap)); 4125 PetscCall(PetscLayoutSetUp(B->cmap)); 4126 4127 PetscCall(MatGetSize(B, &m, &n)); 4128 PetscCall(PetscMalloc1(m + 1, &nnz)); 4129 for (i = 0; i < m; i++) { 4130 nz = Ii[i + 1] - Ii[i]; 4131 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT, i, nz); 4132 nnz[i] = nz; 4133 } 4134 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 4135 PetscCall(PetscFree(nnz)); 4136 4137 for (i = 0; i < m; i++) PetscCall(MatSetValues_SeqAIJ(B, 1, &i, Ii[i + 1] - Ii[i], J + Ii[i], v ? v + Ii[i] : NULL, INSERT_VALUES)); 4138 4139 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 4140 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 4141 4142 PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE)); 4143 PetscFunctionReturn(PETSC_SUCCESS); 4144 } 4145 4146 /*@ 4147 MatSeqAIJKron - Computes C, the Kronecker product of A and B. 4148 4149 Input Parameters: 4150 + A - left-hand side matrix 4151 . B - right-hand side matrix 4152 - reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX` 4153 4154 Output Parameter: 4155 . C - Kronecker product of A and B 4156 4157 Level: intermediate 4158 4159 Note: 4160 `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the product matrix has not changed from that last call to `MatSeqAIJKron()`. 4161 4162 .seealso: `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATKAIJ`, `MatReuse` 4163 @*/ 4164 PetscErrorCode MatSeqAIJKron(Mat A, Mat B, MatReuse reuse, Mat *C) 4165 { 4166 PetscFunctionBegin; 4167 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4168 PetscValidType(A, 1); 4169 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 4170 PetscValidType(B, 2); 4171 PetscValidPointer(C, 4); 4172 if (reuse == MAT_REUSE_MATRIX) { 4173 PetscValidHeaderSpecific(*C, MAT_CLASSID, 4); 4174 PetscValidType(*C, 4); 4175 } 4176 PetscTryMethod(A, "MatSeqAIJKron_C", (Mat, Mat, MatReuse, Mat *), (A, B, reuse, C)); 4177 PetscFunctionReturn(PETSC_SUCCESS); 4178 } 4179 4180 PetscErrorCode MatSeqAIJKron_SeqAIJ(Mat A, Mat B, MatReuse reuse, Mat *C) 4181 { 4182 Mat newmat; 4183 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 4184 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 4185 PetscScalar *v; 4186 const PetscScalar *aa, *ba; 4187 PetscInt *i, *j, m, n, p, q, nnz = 0, am = A->rmap->n, bm = B->rmap->n, an = A->cmap->n, bn = B->cmap->n; 4188 PetscBool flg; 4189 4190 PetscFunctionBegin; 4191 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4192 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4193 PetscCheck(!B->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4194 PetscCheck(B->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4195 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &flg)); 4196 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatType %s", ((PetscObject)B)->type_name); 4197 PetscCheck(reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatReuse %d", (int)reuse); 4198 if (reuse == MAT_INITIAL_MATRIX) { 4199 PetscCall(PetscMalloc2(am * bm + 1, &i, a->i[am] * b->i[bm], &j)); 4200 PetscCall(MatCreate(PETSC_COMM_SELF, &newmat)); 4201 PetscCall(MatSetSizes(newmat, am * bm, an * bn, am * bm, an * bn)); 4202 PetscCall(MatSetType(newmat, MATAIJ)); 4203 i[0] = 0; 4204 for (m = 0; m < am; ++m) { 4205 for (p = 0; p < bm; ++p) { 4206 i[m * bm + p + 1] = i[m * bm + p] + (a->i[m + 1] - a->i[m]) * (b->i[p + 1] - b->i[p]); 4207 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4208 for (q = b->i[p]; q < b->i[p + 1]; ++q) j[nnz++] = a->j[n] * bn + b->j[q]; 4209 } 4210 } 4211 } 4212 PetscCall(MatSeqAIJSetPreallocationCSR(newmat, i, j, NULL)); 4213 *C = newmat; 4214 PetscCall(PetscFree2(i, j)); 4215 nnz = 0; 4216 } 4217 PetscCall(MatSeqAIJGetArray(*C, &v)); 4218 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4219 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 4220 for (m = 0; m < am; ++m) { 4221 for (p = 0; p < bm; ++p) { 4222 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4223 for (q = b->i[p]; q < b->i[p + 1]; ++q) v[nnz++] = aa[n] * ba[q]; 4224 } 4225 } 4226 } 4227 PetscCall(MatSeqAIJRestoreArray(*C, &v)); 4228 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 4229 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 4230 PetscFunctionReturn(PETSC_SUCCESS); 4231 } 4232 4233 #include <../src/mat/impls/dense/seq/dense.h> 4234 #include <petsc/private/kernels/petscaxpy.h> 4235 4236 /* 4237 Computes (B'*A')' since computing B*A directly is untenable 4238 4239 n p p 4240 [ ] [ ] [ ] 4241 m [ A ] * n [ B ] = m [ C ] 4242 [ ] [ ] [ ] 4243 4244 */ 4245 PetscErrorCode MatMatMultNumeric_SeqDense_SeqAIJ(Mat A, Mat B, Mat C) 4246 { 4247 Mat_SeqDense *sub_a = (Mat_SeqDense *)A->data; 4248 Mat_SeqAIJ *sub_b = (Mat_SeqAIJ *)B->data; 4249 Mat_SeqDense *sub_c = (Mat_SeqDense *)C->data; 4250 PetscInt i, j, n, m, q, p; 4251 const PetscInt *ii, *idx; 4252 const PetscScalar *b, *a, *a_q; 4253 PetscScalar *c, *c_q; 4254 PetscInt clda = sub_c->lda; 4255 PetscInt alda = sub_a->lda; 4256 4257 PetscFunctionBegin; 4258 m = A->rmap->n; 4259 n = A->cmap->n; 4260 p = B->cmap->n; 4261 a = sub_a->v; 4262 b = sub_b->a; 4263 c = sub_c->v; 4264 if (clda == m) { 4265 PetscCall(PetscArrayzero(c, m * p)); 4266 } else { 4267 for (j = 0; j < p; j++) 4268 for (i = 0; i < m; i++) c[j * clda + i] = 0.0; 4269 } 4270 ii = sub_b->i; 4271 idx = sub_b->j; 4272 for (i = 0; i < n; i++) { 4273 q = ii[i + 1] - ii[i]; 4274 while (q-- > 0) { 4275 c_q = c + clda * (*idx); 4276 a_q = a + alda * i; 4277 PetscKernelAXPY(c_q, *b, a_q, m); 4278 idx++; 4279 b++; 4280 } 4281 } 4282 PetscFunctionReturn(PETSC_SUCCESS); 4283 } 4284 4285 PetscErrorCode MatMatMultSymbolic_SeqDense_SeqAIJ(Mat A, Mat B, PetscReal fill, Mat C) 4286 { 4287 PetscInt m = A->rmap->n, n = B->cmap->n; 4288 PetscBool cisdense; 4289 4290 PetscFunctionBegin; 4291 PetscCheck(A->cmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "A->cmap->n %" PetscInt_FMT " != B->rmap->n %" PetscInt_FMT, A->cmap->n, B->rmap->n); 4292 PetscCall(MatSetSizes(C, m, n, m, n)); 4293 PetscCall(MatSetBlockSizesFromMats(C, A, B)); 4294 PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATSEQDENSECUDA, MATSEQDENSEHIP, "")); 4295 if (!cisdense) PetscCall(MatSetType(C, MATDENSE)); 4296 PetscCall(MatSetUp(C)); 4297 4298 C->ops->matmultnumeric = MatMatMultNumeric_SeqDense_SeqAIJ; 4299 PetscFunctionReturn(PETSC_SUCCESS); 4300 } 4301 4302 /* ----------------------------------------------------------------*/ 4303 /*MC 4304 MATSEQAIJ - MATSEQAIJ = "seqaij" - A matrix type to be used for sequential sparse matrices, 4305 based on compressed sparse row format. 4306 4307 Options Database Keys: 4308 . -mat_type seqaij - sets the matrix type to "seqaij" during a call to MatSetFromOptions() 4309 4310 Level: beginner 4311 4312 Notes: 4313 `MatSetValues()` may be called for this matrix type with a NULL argument for the numerical values, 4314 in this case the values associated with the rows and columns one passes in are set to zero 4315 in the matrix 4316 4317 `MatSetOptions`(,`MAT_STRUCTURE_ONLY`,`PETSC_TRUE`) may be called for this matrix type. In this no 4318 space is allocated for the nonzero entries and any entries passed with `MatSetValues()` are ignored 4319 4320 Developer Note: 4321 It would be nice if all matrix formats supported passing NULL in for the numerical values 4322 4323 .seealso: `MatCreateSeqAIJ()`, `MatSetFromOptions()`, `MatSetType()`, `MatCreate()`, `MatType`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4324 M*/ 4325 4326 /*MC 4327 MATAIJ - MATAIJ = "aij" - A matrix type to be used for sparse matrices. 4328 4329 This matrix type is identical to `MATSEQAIJ` when constructed with a single process communicator, 4330 and `MATMPIAIJ` otherwise. As a result, for single process communicators, 4331 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4332 for communicators controlling multiple processes. It is recommended that you call both of 4333 the above preallocation routines for simplicity. 4334 4335 Options Database Keys: 4336 . -mat_type aij - sets the matrix type to "aij" during a call to `MatSetFromOptions()` 4337 4338 Note: 4339 Subclasses include `MATAIJCUSPARSE`, `MATAIJPERM`, `MATAIJSELL`, `MATAIJMKL`, `MATAIJCRL`, and also automatically switches over to use inodes when 4340 enough exist. 4341 4342 Level: beginner 4343 4344 .seealso: `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATMPIAIJ`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4345 M*/ 4346 4347 /*MC 4348 MATAIJCRL - MATAIJCRL = "aijcrl" - A matrix type to be used for sparse matrices. 4349 4350 This matrix type is identical to `MATSEQAIJCRL` when constructed with a single process communicator, 4351 and `MATMPIAIJCRL` otherwise. As a result, for single process communicators, 4352 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4353 for communicators controlling multiple processes. It is recommended that you call both of 4354 the above preallocation routines for simplicity. 4355 4356 Options Database Keys: 4357 . -mat_type aijcrl - sets the matrix type to "aijcrl" during a call to `MatSetFromOptions()` 4358 4359 Level: beginner 4360 4361 .seealso: `MatCreateMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL` 4362 M*/ 4363 4364 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCRL(Mat, MatType, MatReuse, Mat *); 4365 #if defined(PETSC_HAVE_ELEMENTAL) 4366 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat, MatType, MatReuse, Mat *); 4367 #endif 4368 #if defined(PETSC_HAVE_SCALAPACK) 4369 PETSC_INTERN PetscErrorCode MatConvert_AIJ_ScaLAPACK(Mat, MatType, MatReuse, Mat *); 4370 #endif 4371 #if defined(PETSC_HAVE_HYPRE) 4372 PETSC_INTERN PetscErrorCode MatConvert_AIJ_HYPRE(Mat A, MatType, MatReuse, Mat *); 4373 #endif 4374 4375 PETSC_EXTERN PetscErrorCode MatConvert_SeqAIJ_SeqSELL(Mat, MatType, MatReuse, Mat *); 4376 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat, MatType, MatReuse, Mat *); 4377 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat); 4378 4379 /*@C 4380 MatSeqAIJGetArray - gives read/write access to the array where the data for a `MATSEQAIJ` matrix is stored 4381 4382 Not Collective 4383 4384 Input Parameter: 4385 . mat - a `MATSEQAIJ` matrix 4386 4387 Output Parameter: 4388 . array - pointer to the data 4389 4390 Level: intermediate 4391 4392 Fortran Note: 4393 `MatSeqAIJGetArray()` Fortran binding is deprecated (since PETSc 3.19), use `MatSeqAIJGetArrayF90()` 4394 4395 .seealso: `MatSeqAIJRestoreArray()`, `MatSeqAIJGetArrayF90()` 4396 @*/ 4397 PetscErrorCode MatSeqAIJGetArray(Mat A, PetscScalar **array) 4398 { 4399 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4400 4401 PetscFunctionBegin; 4402 if (aij->ops->getarray) { 4403 PetscCall((*aij->ops->getarray)(A, array)); 4404 } else { 4405 *array = aij->a; 4406 } 4407 PetscFunctionReturn(PETSC_SUCCESS); 4408 } 4409 4410 /*@C 4411 MatSeqAIJRestoreArray - returns access to the array where the data for a `MATSEQAIJ` matrix is stored obtained by `MatSeqAIJGetArray()` 4412 4413 Not Collective 4414 4415 Input Parameters: 4416 + mat - a `MATSEQAIJ` matrix 4417 - array - pointer to the data 4418 4419 Level: intermediate 4420 4421 Fortran Note: 4422 `MatSeqAIJRestoreArray()` Fortran binding is deprecated (since PETSc 3.19), use `MatSeqAIJRestoreArrayF90()` 4423 4424 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayF90()` 4425 @*/ 4426 PetscErrorCode MatSeqAIJRestoreArray(Mat A, PetscScalar **array) 4427 { 4428 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4429 4430 PetscFunctionBegin; 4431 if (aij->ops->restorearray) { 4432 PetscCall((*aij->ops->restorearray)(A, array)); 4433 } else { 4434 *array = NULL; 4435 } 4436 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4437 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4438 PetscFunctionReturn(PETSC_SUCCESS); 4439 } 4440 4441 /*@C 4442 MatSeqAIJGetArrayRead - gives read-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4443 4444 Not Collective; No Fortran Support 4445 4446 Input Parameter: 4447 . mat - a `MATSEQAIJ` matrix 4448 4449 Output Parameter: 4450 . array - pointer to the data 4451 4452 Level: intermediate 4453 4454 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4455 @*/ 4456 PetscErrorCode MatSeqAIJGetArrayRead(Mat A, const PetscScalar **array) 4457 { 4458 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4459 4460 PetscFunctionBegin; 4461 if (aij->ops->getarrayread) { 4462 PetscCall((*aij->ops->getarrayread)(A, array)); 4463 } else { 4464 *array = aij->a; 4465 } 4466 PetscFunctionReturn(PETSC_SUCCESS); 4467 } 4468 4469 /*@C 4470 MatSeqAIJRestoreArrayRead - restore the read-only access array obtained from `MatSeqAIJGetArrayRead()` 4471 4472 Not Collective; No Fortran Support 4473 4474 Input Parameter: 4475 . mat - a `MATSEQAIJ` matrix 4476 4477 Output Parameter: 4478 . array - pointer to the data 4479 4480 Level: intermediate 4481 4482 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4483 @*/ 4484 PetscErrorCode MatSeqAIJRestoreArrayRead(Mat A, const PetscScalar **array) 4485 { 4486 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4487 4488 PetscFunctionBegin; 4489 if (aij->ops->restorearrayread) { 4490 PetscCall((*aij->ops->restorearrayread)(A, array)); 4491 } else { 4492 *array = NULL; 4493 } 4494 PetscFunctionReturn(PETSC_SUCCESS); 4495 } 4496 4497 /*@C 4498 MatSeqAIJGetArrayWrite - gives write-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4499 4500 Not Collective; No Fortran Support 4501 4502 Input Parameter: 4503 . mat - a `MATSEQAIJ` matrix 4504 4505 Output Parameter: 4506 . array - pointer to the data 4507 4508 Level: intermediate 4509 4510 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4511 @*/ 4512 PetscErrorCode MatSeqAIJGetArrayWrite(Mat A, PetscScalar **array) 4513 { 4514 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4515 4516 PetscFunctionBegin; 4517 if (aij->ops->getarraywrite) { 4518 PetscCall((*aij->ops->getarraywrite)(A, array)); 4519 } else { 4520 *array = aij->a; 4521 } 4522 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4523 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4524 PetscFunctionReturn(PETSC_SUCCESS); 4525 } 4526 4527 /*@C 4528 MatSeqAIJRestoreArrayWrite - restore the read-only access array obtained from MatSeqAIJGetArrayRead 4529 4530 Not Collective; No Fortran Support 4531 4532 Input Parameter: 4533 . mat - a MATSEQAIJ matrix 4534 4535 Output Parameter: 4536 . array - pointer to the data 4537 4538 Level: intermediate 4539 4540 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4541 @*/ 4542 PetscErrorCode MatSeqAIJRestoreArrayWrite(Mat A, PetscScalar **array) 4543 { 4544 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4545 4546 PetscFunctionBegin; 4547 if (aij->ops->restorearraywrite) { 4548 PetscCall((*aij->ops->restorearraywrite)(A, array)); 4549 } else { 4550 *array = NULL; 4551 } 4552 PetscFunctionReturn(PETSC_SUCCESS); 4553 } 4554 4555 /*@C 4556 MatSeqAIJGetCSRAndMemType - Get the CSR arrays and the memory type of the `MATSEQAIJ` matrix 4557 4558 Not Collective; No Fortran Support 4559 4560 Input Parameter: 4561 . mat - a matrix of type `MATSEQAIJ` or its subclasses 4562 4563 Output Parameters: 4564 + i - row map array of the matrix 4565 . j - column index array of the matrix 4566 . a - data array of the matrix 4567 - memtype - memory type of the arrays 4568 4569 Notes: 4570 Any of the output parameters can be NULL, in which case the corresponding value is not returned. 4571 If mat is a device matrix, the arrays are on the device. Otherwise, they are on the host. 4572 4573 One can call this routine on a preallocated but not assembled matrix to just get the memory of the CSR underneath the matrix. 4574 If the matrix is assembled, the data array 'a' is guaranteed to have the latest values of the matrix. 4575 4576 Level: Developer 4577 4578 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4579 @*/ 4580 PetscErrorCode MatSeqAIJGetCSRAndMemType(Mat mat, const PetscInt **i, const PetscInt **j, PetscScalar **a, PetscMemType *mtype) 4581 { 4582 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 4583 4584 PetscFunctionBegin; 4585 PetscCheck(mat->preallocated, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "matrix is not preallocated"); 4586 if (aij->ops->getcsrandmemtype) { 4587 PetscCall((*aij->ops->getcsrandmemtype)(mat, i, j, a, mtype)); 4588 } else { 4589 if (i) *i = aij->i; 4590 if (j) *j = aij->j; 4591 if (a) *a = aij->a; 4592 if (mtype) *mtype = PETSC_MEMTYPE_HOST; 4593 } 4594 PetscFunctionReturn(PETSC_SUCCESS); 4595 } 4596 4597 /*@C 4598 MatSeqAIJGetMaxRowNonzeros - returns the maximum number of nonzeros in any row 4599 4600 Not Collective 4601 4602 Input Parameter: 4603 . mat - a `MATSEQAIJ` matrix 4604 4605 Output Parameter: 4606 . nz - the maximum number of nonzeros in any row 4607 4608 Level: intermediate 4609 4610 .seealso: `MatSeqAIJRestoreArray()`, `MatSeqAIJGetArrayF90()` 4611 @*/ 4612 PetscErrorCode MatSeqAIJGetMaxRowNonzeros(Mat A, PetscInt *nz) 4613 { 4614 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4615 4616 PetscFunctionBegin; 4617 *nz = aij->rmax; 4618 PetscFunctionReturn(PETSC_SUCCESS); 4619 } 4620 4621 PetscErrorCode MatSetPreallocationCOO_SeqAIJ(Mat mat, PetscCount coo_n, PetscInt coo_i[], PetscInt coo_j[]) 4622 { 4623 MPI_Comm comm; 4624 PetscInt *i, *j; 4625 PetscInt M, N, row; 4626 PetscCount k, p, q, nneg, nnz, start, end; /* Index the coo array, so use PetscCount as their type */ 4627 PetscInt *Ai; /* Change to PetscCount once we use it for row pointers */ 4628 PetscInt *Aj; 4629 PetscScalar *Aa; 4630 Mat_SeqAIJ *seqaij = (Mat_SeqAIJ *)(mat->data); 4631 MatType rtype; 4632 PetscCount *perm, *jmap; 4633 4634 PetscFunctionBegin; 4635 PetscCall(MatResetPreallocationCOO_SeqAIJ(mat)); 4636 PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 4637 PetscCall(MatGetSize(mat, &M, &N)); 4638 i = coo_i; 4639 j = coo_j; 4640 PetscCall(PetscMalloc1(coo_n, &perm)); 4641 for (k = 0; k < coo_n; k++) { /* Ignore entries with negative row or col indices */ 4642 if (j[k] < 0) i[k] = -1; 4643 perm[k] = k; 4644 } 4645 4646 /* Sort by row */ 4647 PetscCall(PetscSortIntWithIntCountArrayPair(coo_n, i, j, perm)); 4648 for (k = 0; k < coo_n; k++) { 4649 if (i[k] >= 0) break; 4650 } /* Advance k to the first row with a non-negative index */ 4651 nneg = k; 4652 PetscCall(PetscMalloc1(coo_n - nneg + 1, &jmap)); /* +1 to make a CSR-like data structure. jmap[i] originally is the number of repeats for i-th nonzero */ 4653 nnz = 0; /* Total number of unique nonzeros to be counted */ 4654 jmap++; /* Inc jmap by 1 for convenience */ 4655 4656 PetscCall(PetscCalloc1(M + 1, &Ai)); /* CSR of A */ 4657 PetscCall(PetscMalloc1(coo_n - nneg, &Aj)); /* We have at most coo_n-nneg unique nonzeros */ 4658 4659 /* In each row, sort by column, then unique column indices to get row length */ 4660 Ai++; /* Inc by 1 for convenience */ 4661 q = 0; /* q-th unique nonzero, with q starting from 0 */ 4662 while (k < coo_n) { 4663 row = i[k]; 4664 start = k; /* [start,end) indices for this row */ 4665 while (k < coo_n && i[k] == row) k++; 4666 end = k; 4667 PetscCall(PetscSortIntWithCountArray(end - start, j + start, perm + start)); 4668 /* Find number of unique col entries in this row */ 4669 Aj[q] = j[start]; /* Log the first nonzero in this row */ 4670 jmap[q] = 1; /* Number of repeats of this nozero entry */ 4671 Ai[row] = 1; 4672 nnz++; 4673 4674 for (p = start + 1; p < end; p++) { /* Scan remaining nonzero in this row */ 4675 if (j[p] != j[p - 1]) { /* Meet a new nonzero */ 4676 q++; 4677 jmap[q] = 1; 4678 Aj[q] = j[p]; 4679 Ai[row]++; 4680 nnz++; 4681 } else { 4682 jmap[q]++; 4683 } 4684 } 4685 q++; /* Move to next row and thus next unique nonzero */ 4686 } 4687 4688 Ai--; /* Back to the beginning of Ai[] */ 4689 for (k = 0; k < M; k++) Ai[k + 1] += Ai[k]; 4690 jmap--; /* Back to the beginning of jmap[] */ 4691 jmap[0] = 0; 4692 for (k = 0; k < nnz; k++) jmap[k + 1] += jmap[k]; 4693 if (nnz < coo_n - nneg) { /* Realloc with actual number of unique nonzeros */ 4694 PetscCount *jmap_new; 4695 PetscInt *Aj_new; 4696 4697 PetscCall(PetscMalloc1(nnz + 1, &jmap_new)); 4698 PetscCall(PetscArraycpy(jmap_new, jmap, nnz + 1)); 4699 PetscCall(PetscFree(jmap)); 4700 jmap = jmap_new; 4701 4702 PetscCall(PetscMalloc1(nnz, &Aj_new)); 4703 PetscCall(PetscArraycpy(Aj_new, Aj, nnz)); 4704 PetscCall(PetscFree(Aj)); 4705 Aj = Aj_new; 4706 } 4707 4708 if (nneg) { /* Discard heading entries with negative indices in perm[], as we'll access it from index 0 in MatSetValuesCOO */ 4709 PetscCount *perm_new; 4710 4711 PetscCall(PetscMalloc1(coo_n - nneg, &perm_new)); 4712 PetscCall(PetscArraycpy(perm_new, perm + nneg, coo_n - nneg)); 4713 PetscCall(PetscFree(perm)); 4714 perm = perm_new; 4715 } 4716 4717 PetscCall(MatGetRootType_Private(mat, &rtype)); 4718 PetscCall(PetscCalloc1(nnz, &Aa)); /* Zero the matrix */ 4719 PetscCall(MatSetSeqAIJWithArrays_private(PETSC_COMM_SELF, M, N, Ai, Aj, Aa, rtype, mat)); 4720 4721 seqaij->singlemalloc = PETSC_FALSE; /* Ai, Aj and Aa are not allocated in one big malloc */ 4722 seqaij->free_a = seqaij->free_ij = PETSC_TRUE; /* Let newmat own Ai, Aj and Aa */ 4723 /* Record COO fields */ 4724 seqaij->coo_n = coo_n; 4725 seqaij->Atot = coo_n - nneg; /* Annz is seqaij->nz, so no need to record that again */ 4726 seqaij->jmap = jmap; /* of length nnz+1 */ 4727 seqaij->perm = perm; 4728 PetscFunctionReturn(PETSC_SUCCESS); 4729 } 4730 4731 static PetscErrorCode MatSetValuesCOO_SeqAIJ(Mat A, const PetscScalar v[], InsertMode imode) 4732 { 4733 Mat_SeqAIJ *aseq = (Mat_SeqAIJ *)A->data; 4734 PetscCount i, j, Annz = aseq->nz; 4735 PetscCount *perm = aseq->perm, *jmap = aseq->jmap; 4736 PetscScalar *Aa; 4737 4738 PetscFunctionBegin; 4739 PetscCall(MatSeqAIJGetArray(A, &Aa)); 4740 for (i = 0; i < Annz; i++) { 4741 PetscScalar sum = 0.0; 4742 for (j = jmap[i]; j < jmap[i + 1]; j++) sum += v[perm[j]]; 4743 Aa[i] = (imode == INSERT_VALUES ? 0.0 : Aa[i]) + sum; 4744 } 4745 PetscCall(MatSeqAIJRestoreArray(A, &Aa)); 4746 PetscFunctionReturn(PETSC_SUCCESS); 4747 } 4748 4749 #if defined(PETSC_HAVE_CUDA) 4750 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCUSPARSE(Mat, MatType, MatReuse, Mat *); 4751 #endif 4752 #if defined(PETSC_HAVE_HIP) 4753 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJHIPSPARSE(Mat, MatType, MatReuse, Mat *); 4754 #endif 4755 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4756 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJKokkos(Mat, MatType, MatReuse, Mat *); 4757 #endif 4758 4759 PETSC_EXTERN PetscErrorCode MatCreate_SeqAIJ(Mat B) 4760 { 4761 Mat_SeqAIJ *b; 4762 PetscMPIInt size; 4763 4764 PetscFunctionBegin; 4765 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size)); 4766 PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Comm must be of size 1"); 4767 4768 PetscCall(PetscNew(&b)); 4769 4770 B->data = (void *)b; 4771 4772 PetscCall(PetscMemcpy(B->ops, &MatOps_Values, sizeof(struct _MatOps))); 4773 if (B->sortedfull) B->ops->setvalues = MatSetValues_SeqAIJ_SortedFull; 4774 4775 b->row = NULL; 4776 b->col = NULL; 4777 b->icol = NULL; 4778 b->reallocs = 0; 4779 b->ignorezeroentries = PETSC_FALSE; 4780 b->roworiented = PETSC_TRUE; 4781 b->nonew = 0; 4782 b->diag = NULL; 4783 b->solve_work = NULL; 4784 B->spptr = NULL; 4785 b->saved_values = NULL; 4786 b->idiag = NULL; 4787 b->mdiag = NULL; 4788 b->ssor_work = NULL; 4789 b->omega = 1.0; 4790 b->fshift = 0.0; 4791 b->idiagvalid = PETSC_FALSE; 4792 b->ibdiagvalid = PETSC_FALSE; 4793 b->keepnonzeropattern = PETSC_FALSE; 4794 4795 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4796 #if defined(PETSC_HAVE_MATLAB) 4797 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEnginePut_C", MatlabEnginePut_SeqAIJ)); 4798 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEngineGet_C", MatlabEngineGet_SeqAIJ)); 4799 #endif 4800 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetColumnIndices_C", MatSeqAIJSetColumnIndices_SeqAIJ)); 4801 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_SeqAIJ)); 4802 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_SeqAIJ)); 4803 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsbaij_C", MatConvert_SeqAIJ_SeqSBAIJ)); 4804 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqbaij_C", MatConvert_SeqAIJ_SeqBAIJ)); 4805 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijperm_C", MatConvert_SeqAIJ_SeqAIJPERM)); 4806 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijsell_C", MatConvert_SeqAIJ_SeqAIJSELL)); 4807 #if defined(PETSC_HAVE_MKL_SPARSE) 4808 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijmkl_C", MatConvert_SeqAIJ_SeqAIJMKL)); 4809 #endif 4810 #if defined(PETSC_HAVE_CUDA) 4811 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcusparse_C", MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 4812 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4813 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", MatProductSetFromOptions_SeqAIJ)); 4814 #endif 4815 #if defined(PETSC_HAVE_HIP) 4816 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijhipsparse_C", MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 4817 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4818 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", MatProductSetFromOptions_SeqAIJ)); 4819 #endif 4820 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4821 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijkokkos_C", MatConvert_SeqAIJ_SeqAIJKokkos)); 4822 #endif 4823 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcrl_C", MatConvert_SeqAIJ_SeqAIJCRL)); 4824 #if defined(PETSC_HAVE_ELEMENTAL) 4825 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_elemental_C", MatConvert_SeqAIJ_Elemental)); 4826 #endif 4827 #if defined(PETSC_HAVE_SCALAPACK) 4828 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_scalapack_C", MatConvert_AIJ_ScaLAPACK)); 4829 #endif 4830 #if defined(PETSC_HAVE_HYPRE) 4831 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_hypre_C", MatConvert_AIJ_HYPRE)); 4832 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", MatProductSetFromOptions_Transpose_AIJ_AIJ)); 4833 #endif 4834 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqdense_C", MatConvert_SeqAIJ_SeqDense)); 4835 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsell_C", MatConvert_SeqAIJ_SeqSELL)); 4836 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_is_C", MatConvert_XAIJ_IS)); 4837 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_SeqAIJ)); 4838 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsHermitianTranspose_C", MatIsTranspose_SeqAIJ)); 4839 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocation_C", MatSeqAIJSetPreallocation_SeqAIJ)); 4840 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetPreallocation_C", MatResetPreallocation_SeqAIJ)); 4841 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocationCSR_C", MatSeqAIJSetPreallocationCSR_SeqAIJ)); 4842 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatReorderForNonzeroDiagonal_C", MatReorderForNonzeroDiagonal_SeqAIJ)); 4843 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_is_seqaij_C", MatProductSetFromOptions_IS_XAIJ)); 4844 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqdense_seqaij_C", MatProductSetFromOptions_SeqDense_SeqAIJ)); 4845 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4846 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJKron_C", MatSeqAIJKron_SeqAIJ)); 4847 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_SeqAIJ)); 4848 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetValuesCOO_C", MatSetValuesCOO_SeqAIJ)); 4849 PetscCall(MatCreate_SeqAIJ_Inode(B)); 4850 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4851 PetscCall(MatSeqAIJSetTypeFromOptions(B)); /* this allows changing the matrix subtype to say MATSEQAIJPERM */ 4852 PetscFunctionReturn(PETSC_SUCCESS); 4853 } 4854 4855 /* 4856 Given a matrix generated with MatGetFactor() duplicates all the information in A into C 4857 */ 4858 PetscErrorCode MatDuplicateNoCreate_SeqAIJ(Mat C, Mat A, MatDuplicateOption cpvalues, PetscBool mallocmatspace) 4859 { 4860 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data, *a = (Mat_SeqAIJ *)A->data; 4861 PetscInt m = A->rmap->n, i; 4862 4863 PetscFunctionBegin; 4864 PetscCheck(A->assembled || cpvalues == MAT_DO_NOT_COPY_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot duplicate unassembled matrix"); 4865 4866 C->factortype = A->factortype; 4867 c->row = NULL; 4868 c->col = NULL; 4869 c->icol = NULL; 4870 c->reallocs = 0; 4871 4872 C->assembled = A->assembled; 4873 C->preallocated = A->preallocated; 4874 4875 if (A->preallocated) { 4876 PetscCall(PetscLayoutReference(A->rmap, &C->rmap)); 4877 PetscCall(PetscLayoutReference(A->cmap, &C->cmap)); 4878 4879 PetscCall(PetscMalloc1(m, &c->imax)); 4880 PetscCall(PetscMemcpy(c->imax, a->imax, m * sizeof(PetscInt))); 4881 PetscCall(PetscMalloc1(m, &c->ilen)); 4882 PetscCall(PetscMemcpy(c->ilen, a->ilen, m * sizeof(PetscInt))); 4883 4884 /* allocate the matrix space */ 4885 if (mallocmatspace) { 4886 PetscCall(PetscMalloc3(a->i[m], &c->a, a->i[m], &c->j, m + 1, &c->i)); 4887 4888 c->singlemalloc = PETSC_TRUE; 4889 4890 PetscCall(PetscArraycpy(c->i, a->i, m + 1)); 4891 if (m > 0) { 4892 PetscCall(PetscArraycpy(c->j, a->j, a->i[m])); 4893 if (cpvalues == MAT_COPY_VALUES) { 4894 const PetscScalar *aa; 4895 4896 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4897 PetscCall(PetscArraycpy(c->a, aa, a->i[m])); 4898 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4899 } else { 4900 PetscCall(PetscArrayzero(c->a, a->i[m])); 4901 } 4902 } 4903 } 4904 4905 c->ignorezeroentries = a->ignorezeroentries; 4906 c->roworiented = a->roworiented; 4907 c->nonew = a->nonew; 4908 if (a->diag) { 4909 PetscCall(PetscMalloc1(m + 1, &c->diag)); 4910 PetscCall(PetscMemcpy(c->diag, a->diag, m * sizeof(PetscInt))); 4911 } else c->diag = NULL; 4912 4913 c->solve_work = NULL; 4914 c->saved_values = NULL; 4915 c->idiag = NULL; 4916 c->ssor_work = NULL; 4917 c->keepnonzeropattern = a->keepnonzeropattern; 4918 c->free_a = PETSC_TRUE; 4919 c->free_ij = PETSC_TRUE; 4920 4921 c->rmax = a->rmax; 4922 c->nz = a->nz; 4923 c->maxnz = a->nz; /* Since we allocate exactly the right amount */ 4924 4925 c->compressedrow.use = a->compressedrow.use; 4926 c->compressedrow.nrows = a->compressedrow.nrows; 4927 if (a->compressedrow.use) { 4928 i = a->compressedrow.nrows; 4929 PetscCall(PetscMalloc2(i + 1, &c->compressedrow.i, i, &c->compressedrow.rindex)); 4930 PetscCall(PetscArraycpy(c->compressedrow.i, a->compressedrow.i, i + 1)); 4931 PetscCall(PetscArraycpy(c->compressedrow.rindex, a->compressedrow.rindex, i)); 4932 } else { 4933 c->compressedrow.use = PETSC_FALSE; 4934 c->compressedrow.i = NULL; 4935 c->compressedrow.rindex = NULL; 4936 } 4937 c->nonzerorowcnt = a->nonzerorowcnt; 4938 C->nonzerostate = A->nonzerostate; 4939 4940 PetscCall(MatDuplicate_SeqAIJ_Inode(A, cpvalues, &C)); 4941 } 4942 PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist, &((PetscObject)C)->qlist)); 4943 PetscFunctionReturn(PETSC_SUCCESS); 4944 } 4945 4946 PetscErrorCode MatDuplicate_SeqAIJ(Mat A, MatDuplicateOption cpvalues, Mat *B) 4947 { 4948 PetscFunctionBegin; 4949 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 4950 PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->n, A->cmap->n)); 4951 if (!(A->rmap->n % A->rmap->bs) && !(A->cmap->n % A->cmap->bs)) PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 4952 PetscCall(MatSetType(*B, ((PetscObject)A)->type_name)); 4953 PetscCall(MatDuplicateNoCreate_SeqAIJ(*B, A, cpvalues, PETSC_TRUE)); 4954 PetscFunctionReturn(PETSC_SUCCESS); 4955 } 4956 4957 PetscErrorCode MatLoad_SeqAIJ(Mat newMat, PetscViewer viewer) 4958 { 4959 PetscBool isbinary, ishdf5; 4960 4961 PetscFunctionBegin; 4962 PetscValidHeaderSpecific(newMat, MAT_CLASSID, 1); 4963 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 4964 /* force binary viewer to load .info file if it has not yet done so */ 4965 PetscCall(PetscViewerSetUp(viewer)); 4966 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 4967 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 4968 if (isbinary) { 4969 PetscCall(MatLoad_SeqAIJ_Binary(newMat, viewer)); 4970 } else if (ishdf5) { 4971 #if defined(PETSC_HAVE_HDF5) 4972 PetscCall(MatLoad_AIJ_HDF5(newMat, viewer)); 4973 #else 4974 SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 4975 #endif 4976 } else { 4977 SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "Viewer type %s not yet supported for reading %s matrices", ((PetscObject)viewer)->type_name, ((PetscObject)newMat)->type_name); 4978 } 4979 PetscFunctionReturn(PETSC_SUCCESS); 4980 } 4981 4982 PetscErrorCode MatLoad_SeqAIJ_Binary(Mat mat, PetscViewer viewer) 4983 { 4984 Mat_SeqAIJ *a = (Mat_SeqAIJ *)mat->data; 4985 PetscInt header[4], *rowlens, M, N, nz, sum, rows, cols, i; 4986 4987 PetscFunctionBegin; 4988 PetscCall(PetscViewerSetUp(viewer)); 4989 4990 /* read in matrix header */ 4991 PetscCall(PetscViewerBinaryRead(viewer, header, 4, NULL, PETSC_INT)); 4992 PetscCheck(header[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix object in file"); 4993 M = header[1]; 4994 N = header[2]; 4995 nz = header[3]; 4996 PetscCheck(M >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix row size (%" PetscInt_FMT ") in file is negative", M); 4997 PetscCheck(N >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix column size (%" PetscInt_FMT ") in file is negative", N); 4998 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix stored in special format on disk, cannot load as SeqAIJ"); 4999 5000 /* set block sizes from the viewer's .info file */ 5001 PetscCall(MatLoad_Binary_BlockSizes(mat, viewer)); 5002 /* set local and global sizes if not set already */ 5003 if (mat->rmap->n < 0) mat->rmap->n = M; 5004 if (mat->cmap->n < 0) mat->cmap->n = N; 5005 if (mat->rmap->N < 0) mat->rmap->N = M; 5006 if (mat->cmap->N < 0) mat->cmap->N = N; 5007 PetscCall(PetscLayoutSetUp(mat->rmap)); 5008 PetscCall(PetscLayoutSetUp(mat->cmap)); 5009 5010 /* check if the matrix sizes are correct */ 5011 PetscCall(MatGetSize(mat, &rows, &cols)); 5012 PetscCheck(M == rows && N == cols, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix in file of different sizes (%" PetscInt_FMT ", %" PetscInt_FMT ") than the input matrix (%" PetscInt_FMT ", %" PetscInt_FMT ")", M, N, rows, cols); 5013 5014 /* read in row lengths */ 5015 PetscCall(PetscMalloc1(M, &rowlens)); 5016 PetscCall(PetscViewerBinaryRead(viewer, rowlens, M, NULL, PETSC_INT)); 5017 /* check if sum(rowlens) is same as nz */ 5018 sum = 0; 5019 for (i = 0; i < M; i++) sum += rowlens[i]; 5020 PetscCheck(sum == nz, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Inconsistent matrix data in file: nonzeros = %" PetscInt_FMT ", sum-row-lengths = %" PetscInt_FMT, nz, sum); 5021 /* preallocate and check sizes */ 5022 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(mat, 0, rowlens)); 5023 PetscCall(MatGetSize(mat, &rows, &cols)); 5024 PetscCheck(M == rows && N == cols, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix in file of different length (%" PetscInt_FMT ", %" PetscInt_FMT ") than the input matrix (%" PetscInt_FMT ", %" PetscInt_FMT ")", M, N, rows, cols); 5025 /* store row lengths */ 5026 PetscCall(PetscArraycpy(a->ilen, rowlens, M)); 5027 PetscCall(PetscFree(rowlens)); 5028 5029 /* fill in "i" row pointers */ 5030 a->i[0] = 0; 5031 for (i = 0; i < M; i++) a->i[i + 1] = a->i[i] + a->ilen[i]; 5032 /* read in "j" column indices */ 5033 PetscCall(PetscViewerBinaryRead(viewer, a->j, nz, NULL, PETSC_INT)); 5034 /* read in "a" nonzero values */ 5035 PetscCall(PetscViewerBinaryRead(viewer, a->a, nz, NULL, PETSC_SCALAR)); 5036 5037 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 5038 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 5039 PetscFunctionReturn(PETSC_SUCCESS); 5040 } 5041 5042 PetscErrorCode MatEqual_SeqAIJ(Mat A, Mat B, PetscBool *flg) 5043 { 5044 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data; 5045 const PetscScalar *aa, *ba; 5046 #if defined(PETSC_USE_COMPLEX) 5047 PetscInt k; 5048 #endif 5049 5050 PetscFunctionBegin; 5051 /* If the matrix dimensions are not equal,or no of nonzeros */ 5052 if ((A->rmap->n != B->rmap->n) || (A->cmap->n != B->cmap->n) || (a->nz != b->nz)) { 5053 *flg = PETSC_FALSE; 5054 PetscFunctionReturn(PETSC_SUCCESS); 5055 } 5056 5057 /* if the a->i are the same */ 5058 PetscCall(PetscArraycmp(a->i, b->i, A->rmap->n + 1, flg)); 5059 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5060 5061 /* if a->j are the same */ 5062 PetscCall(PetscArraycmp(a->j, b->j, a->nz, flg)); 5063 if (!*flg) PetscFunctionReturn(PETSC_SUCCESS); 5064 5065 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 5066 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 5067 /* if a->a are the same */ 5068 #if defined(PETSC_USE_COMPLEX) 5069 for (k = 0; k < a->nz; k++) { 5070 if (PetscRealPart(aa[k]) != PetscRealPart(ba[k]) || PetscImaginaryPart(aa[k]) != PetscImaginaryPart(ba[k])) { 5071 *flg = PETSC_FALSE; 5072 PetscFunctionReturn(PETSC_SUCCESS); 5073 } 5074 } 5075 #else 5076 PetscCall(PetscArraycmp(aa, ba, a->nz, flg)); 5077 #endif 5078 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 5079 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 5080 PetscFunctionReturn(PETSC_SUCCESS); 5081 } 5082 5083 /*@ 5084 MatCreateSeqAIJWithArrays - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in CSR format) 5085 provided by the user. 5086 5087 Collective 5088 5089 Input Parameters: 5090 + comm - must be an MPI communicator of size 1 5091 . m - number of rows 5092 . n - number of columns 5093 . i - row indices; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix 5094 . j - column indices 5095 - a - matrix values 5096 5097 Output Parameter: 5098 . mat - the matrix 5099 5100 Level: intermediate 5101 5102 Notes: 5103 The i, j, and a arrays are not copied by this routine, the user must free these arrays 5104 once the matrix is destroyed and not before 5105 5106 You cannot set new nonzero locations into this matrix, that will generate an error. 5107 5108 The i and j indices are 0 based 5109 5110 The format which is used for the sparse matrix input, is equivalent to a 5111 row-major ordering.. i.e for the following matrix, the input data expected is 5112 as shown 5113 5114 $ 1 0 0 5115 $ 2 0 3 5116 $ 4 5 6 5117 $ 5118 $ i = {0,1,3,6} [size = nrow+1 = 3+1] 5119 $ j = {0,0,2,0,1,2} [size = 6]; values must be sorted for each row 5120 $ v = {1,2,3,4,5,6} [size = 6] 5121 5122 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateMPIAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()` 5123 @*/ 5124 PetscErrorCode MatCreateSeqAIJWithArrays(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat) 5125 { 5126 PetscInt ii; 5127 Mat_SeqAIJ *aij; 5128 PetscInt jj; 5129 5130 PetscFunctionBegin; 5131 PetscCheck(m <= 0 || i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i (row indices) must start with 0"); 5132 PetscCall(MatCreate(comm, mat)); 5133 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5134 /* PetscCall(MatSetBlockSizes(*mat,,)); */ 5135 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5136 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, MAT_SKIP_ALLOCATION, NULL)); 5137 aij = (Mat_SeqAIJ *)(*mat)->data; 5138 PetscCall(PetscMalloc1(m, &aij->imax)); 5139 PetscCall(PetscMalloc1(m, &aij->ilen)); 5140 5141 aij->i = i; 5142 aij->j = j; 5143 aij->a = a; 5144 aij->singlemalloc = PETSC_FALSE; 5145 aij->nonew = -1; /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/ 5146 aij->free_a = PETSC_FALSE; 5147 aij->free_ij = PETSC_FALSE; 5148 5149 for (ii = 0, aij->nonzerorowcnt = 0, aij->rmax = 0; ii < m; ii++) { 5150 aij->ilen[ii] = aij->imax[ii] = i[ii + 1] - i[ii]; 5151 if (PetscDefined(USE_DEBUG)) { 5152 PetscCheck(i[ii + 1] - i[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative row length in i (row indices) row = %" PetscInt_FMT " length = %" PetscInt_FMT, ii, i[ii + 1] - i[ii]); 5153 for (jj = i[ii] + 1; jj < i[ii + 1]; jj++) { 5154 PetscCheck(j[jj] >= j[jj - 1], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column entry number %" PetscInt_FMT " (actual column %" PetscInt_FMT ") in row %" PetscInt_FMT " is not sorted", jj - i[ii], j[jj], ii); 5155 PetscCheck(j[jj] != j[jj - 1], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column entry number %" PetscInt_FMT " (actual column %" PetscInt_FMT ") in row %" PetscInt_FMT " is identical to previous entry", jj - i[ii], j[jj], ii); 5156 } 5157 } 5158 } 5159 if (PetscDefined(USE_DEBUG)) { 5160 for (ii = 0; ii < aij->i[m]; ii++) { 5161 PetscCheck(j[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]); 5162 PetscCheck(j[ii] <= n - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column index to large at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]); 5163 } 5164 } 5165 5166 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5167 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5168 PetscFunctionReturn(PETSC_SUCCESS); 5169 } 5170 5171 /*@ 5172 MatCreateSeqAIJFromTriple - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in COO format) 5173 provided by the user. 5174 5175 Collective 5176 5177 Input Parameters: 5178 + comm - must be an MPI communicator of size 1 5179 . m - number of rows 5180 . n - number of columns 5181 . i - row indices 5182 . j - column indices 5183 . a - matrix values 5184 . nz - number of nonzeros 5185 - idx - if the i and j indices start with 1 use `PETSC_TRUE` otherwise use `PETSC_FALSE` 5186 5187 Output Parameter: 5188 . mat - the matrix 5189 5190 Level: intermediate 5191 5192 Example: 5193 For the following matrix, the input data expected is as shown (using 0 based indexing) 5194 .vb 5195 1 0 0 5196 2 0 3 5197 4 5 6 5198 5199 i = {0,1,1,2,2,2} 5200 j = {0,0,2,0,1,2} 5201 v = {1,2,3,4,5,6} 5202 .ve 5203 Notes: 5204 Instead of using this function, users should also consider `MatSetPreallocationCOO()` and `MatSetValuesCOO()`, which allow repeated or remote entries, 5205 and are particularly useful in iterative applications. 5206 5207 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateSeqAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`, `MatSetValuesCOO()`, `MatSetPreallocationCOO()` 5208 @*/ 5209 PetscErrorCode MatCreateSeqAIJFromTriple(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat, PetscInt nz, PetscBool idx) 5210 { 5211 PetscInt ii, *nnz, one = 1, row, col; 5212 5213 PetscFunctionBegin; 5214 PetscCall(PetscCalloc1(m, &nnz)); 5215 for (ii = 0; ii < nz; ii++) nnz[i[ii] - !!idx] += 1; 5216 PetscCall(MatCreate(comm, mat)); 5217 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5218 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5219 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, 0, nnz)); 5220 for (ii = 0; ii < nz; ii++) { 5221 if (idx) { 5222 row = i[ii] - 1; 5223 col = j[ii] - 1; 5224 } else { 5225 row = i[ii]; 5226 col = j[ii]; 5227 } 5228 PetscCall(MatSetValues(*mat, one, &row, one, &col, &a[ii], ADD_VALUES)); 5229 } 5230 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5231 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5232 PetscCall(PetscFree(nnz)); 5233 PetscFunctionReturn(PETSC_SUCCESS); 5234 } 5235 5236 PetscErrorCode MatSeqAIJInvalidateDiagonal(Mat A) 5237 { 5238 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5239 5240 PetscFunctionBegin; 5241 a->idiagvalid = PETSC_FALSE; 5242 a->ibdiagvalid = PETSC_FALSE; 5243 5244 PetscCall(MatSeqAIJInvalidateDiagonal_Inode(A)); 5245 PetscFunctionReturn(PETSC_SUCCESS); 5246 } 5247 5248 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqAIJ(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat) 5249 { 5250 PetscFunctionBegin; 5251 PetscCall(MatCreateMPIMatConcatenateSeqMat_MPIAIJ(comm, inmat, n, scall, outmat)); 5252 PetscFunctionReturn(PETSC_SUCCESS); 5253 } 5254 5255 /* 5256 Permute A into C's *local* index space using rowemb,colemb. 5257 The embedding are supposed to be injections and the above implies that the range of rowemb is a subset 5258 of [0,m), colemb is in [0,n). 5259 If pattern == DIFFERENT_NONZERO_PATTERN, C is preallocated according to A. 5260 */ 5261 PetscErrorCode MatSetSeqMat_SeqAIJ(Mat C, IS rowemb, IS colemb, MatStructure pattern, Mat B) 5262 { 5263 /* If making this function public, change the error returned in this function away from _PLIB. */ 5264 Mat_SeqAIJ *Baij; 5265 PetscBool seqaij; 5266 PetscInt m, n, *nz, i, j, count; 5267 PetscScalar v; 5268 const PetscInt *rowindices, *colindices; 5269 5270 PetscFunctionBegin; 5271 if (!B) PetscFunctionReturn(PETSC_SUCCESS); 5272 /* Check to make sure the target matrix (and embeddings) are compatible with C and each other. */ 5273 PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATSEQAIJ, &seqaij)); 5274 PetscCheck(seqaij, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is of wrong type"); 5275 if (rowemb) { 5276 PetscCall(ISGetLocalSize(rowemb, &m)); 5277 PetscCheck(m == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Row IS of size %" PetscInt_FMT " is incompatible with matrix row size %" PetscInt_FMT, m, B->rmap->n); 5278 } else { 5279 PetscCheck(C->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is row-incompatible with the target matrix"); 5280 } 5281 if (colemb) { 5282 PetscCall(ISGetLocalSize(colemb, &n)); 5283 PetscCheck(n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Diag col IS of size %" PetscInt_FMT " is incompatible with input matrix col size %" PetscInt_FMT, n, B->cmap->n); 5284 } else { 5285 PetscCheck(C->cmap->n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is col-incompatible with the target matrix"); 5286 } 5287 5288 Baij = (Mat_SeqAIJ *)(B->data); 5289 if (pattern == DIFFERENT_NONZERO_PATTERN) { 5290 PetscCall(PetscMalloc1(B->rmap->n, &nz)); 5291 for (i = 0; i < B->rmap->n; i++) nz[i] = Baij->i[i + 1] - Baij->i[i]; 5292 PetscCall(MatSeqAIJSetPreallocation(C, 0, nz)); 5293 PetscCall(PetscFree(nz)); 5294 } 5295 if (pattern == SUBSET_NONZERO_PATTERN) PetscCall(MatZeroEntries(C)); 5296 count = 0; 5297 rowindices = NULL; 5298 colindices = NULL; 5299 if (rowemb) PetscCall(ISGetIndices(rowemb, &rowindices)); 5300 if (colemb) PetscCall(ISGetIndices(colemb, &colindices)); 5301 for (i = 0; i < B->rmap->n; i++) { 5302 PetscInt row; 5303 row = i; 5304 if (rowindices) row = rowindices[i]; 5305 for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) { 5306 PetscInt col; 5307 col = Baij->j[count]; 5308 if (colindices) col = colindices[col]; 5309 v = Baij->a[count]; 5310 PetscCall(MatSetValues(C, 1, &row, 1, &col, &v, INSERT_VALUES)); 5311 ++count; 5312 } 5313 } 5314 /* FIXME: set C's nonzerostate correctly. */ 5315 /* Assembly for C is necessary. */ 5316 C->preallocated = PETSC_TRUE; 5317 C->assembled = PETSC_TRUE; 5318 C->was_assembled = PETSC_FALSE; 5319 PetscFunctionReturn(PETSC_SUCCESS); 5320 } 5321 5322 PetscErrorCode MatEliminateZeros_SeqAIJ(Mat A) 5323 { 5324 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5325 MatScalar *aa = a->a; 5326 PetscInt m = A->rmap->n, fshift = 0, fshift_prev = 0, i, k; 5327 PetscInt *ailen = a->ilen, *imax = a->imax, *ai = a->i, *aj = a->j, rmax = 0; 5328 5329 PetscFunctionBegin; 5330 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot eliminate zeros for unassembled matrix"); 5331 if (m) rmax = ailen[0]; /* determine row with most nonzeros */ 5332 for (i = 1; i <= m; i++) { 5333 /* move each nonzero entry back by the amount of zero slots (fshift) before it*/ 5334 for (k = ai[i - 1]; k < ai[i]; k++) { 5335 if (aa[k] == 0 && aj[k] != i - 1) fshift++; 5336 else { 5337 if (aa[k] == 0 && aj[k] == i - 1) PetscCall(PetscInfo(A, "Keep the diagonal zero at row %" PetscInt_FMT "\n", i - 1)); 5338 aa[k - fshift] = aa[k]; 5339 aj[k - fshift] = aj[k]; 5340 } 5341 } 5342 ai[i - 1] -= fshift_prev; // safe to update ai[i-1] now since it will not be used in the next iteration 5343 fshift_prev = fshift; 5344 /* reset ilen and imax for each row */ 5345 ailen[i - 1] = imax[i - 1] = ai[i] - fshift - ai[i - 1]; 5346 a->nonzerorowcnt += ((ai[i] - fshift - ai[i - 1]) > 0); 5347 rmax = PetscMax(rmax, ailen[i - 1]); 5348 } 5349 if (m) { 5350 ai[m] -= fshift; 5351 a->nz = ai[m]; 5352 } 5353 PetscCall(PetscInfo(A, "Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT "; zeros eliminated: %" PetscInt_FMT "; nonzeros left: %" PetscInt_FMT "\n", m, A->cmap->n, fshift, a->nz)); 5354 A->nonzerostate -= fshift; 5355 A->info.nz_unneeded += (PetscReal)fshift; 5356 a->rmax = rmax; 5357 if (a->inode.use && a->inode.checked) PetscCall(MatSeqAIJCheckInode(A)); 5358 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 5359 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 5360 PetscFunctionReturn(PETSC_SUCCESS); 5361 } 5362 5363 PetscFunctionList MatSeqAIJList = NULL; 5364 5365 /*@C 5366 MatSeqAIJSetType - Converts a `MATSEQAIJ` matrix to a subtype 5367 5368 Collective 5369 5370 Input Parameters: 5371 + mat - the matrix object 5372 - matype - matrix type 5373 5374 Options Database Key: 5375 . -mat_seqaij_type <method> - for example seqaijcrl 5376 5377 Level: intermediate 5378 5379 .seealso: `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType`, `Mat` 5380 @*/ 5381 PetscErrorCode MatSeqAIJSetType(Mat mat, MatType matype) 5382 { 5383 PetscBool sametype; 5384 PetscErrorCode (*r)(Mat, MatType, MatReuse, Mat *); 5385 5386 PetscFunctionBegin; 5387 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 5388 PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype)); 5389 if (sametype) PetscFunctionReturn(PETSC_SUCCESS); 5390 5391 PetscCall(PetscFunctionListFind(MatSeqAIJList, matype, &r)); 5392 PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype); 5393 PetscCall((*r)(mat, matype, MAT_INPLACE_MATRIX, &mat)); 5394 PetscFunctionReturn(PETSC_SUCCESS); 5395 } 5396 5397 /*@C 5398 MatSeqAIJRegister - - Adds a new sub-matrix type for sequential `MATSEQAIJ` matrices 5399 5400 Not Collective 5401 5402 Input Parameters: 5403 + name - name of a new user-defined matrix type, for example `MATSEQAIJCRL` 5404 - function - routine to convert to subtype 5405 5406 Notes: 5407 `MatSeqAIJRegister()` may be called multiple times to add several user-defined solvers. 5408 5409 Then, your matrix can be chosen with the procedural interface at runtime via the option 5410 $ -mat_seqaij_type my_mat 5411 5412 Level: advanced 5413 5414 .seealso: `MatSeqAIJRegisterAll()` 5415 @*/ 5416 PetscErrorCode MatSeqAIJRegister(const char sname[], PetscErrorCode (*function)(Mat, MatType, MatReuse, Mat *)) 5417 { 5418 PetscFunctionBegin; 5419 PetscCall(MatInitializePackage()); 5420 PetscCall(PetscFunctionListAdd(&MatSeqAIJList, sname, function)); 5421 PetscFunctionReturn(PETSC_SUCCESS); 5422 } 5423 5424 PetscBool MatSeqAIJRegisterAllCalled = PETSC_FALSE; 5425 5426 /*@C 5427 MatSeqAIJRegisterAll - Registers all of the matrix subtypes of `MATSSEQAIJ` 5428 5429 Not Collective 5430 5431 Level: advanced 5432 5433 .seealso: `MatRegisterAll()`, `MatSeqAIJRegister()` 5434 @*/ 5435 PetscErrorCode MatSeqAIJRegisterAll(void) 5436 { 5437 PetscFunctionBegin; 5438 if (MatSeqAIJRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 5439 MatSeqAIJRegisterAllCalled = PETSC_TRUE; 5440 5441 PetscCall(MatSeqAIJRegister(MATSEQAIJCRL, MatConvert_SeqAIJ_SeqAIJCRL)); 5442 PetscCall(MatSeqAIJRegister(MATSEQAIJPERM, MatConvert_SeqAIJ_SeqAIJPERM)); 5443 PetscCall(MatSeqAIJRegister(MATSEQAIJSELL, MatConvert_SeqAIJ_SeqAIJSELL)); 5444 #if defined(PETSC_HAVE_MKL_SPARSE) 5445 PetscCall(MatSeqAIJRegister(MATSEQAIJMKL, MatConvert_SeqAIJ_SeqAIJMKL)); 5446 #endif 5447 #if defined(PETSC_HAVE_CUDA) 5448 PetscCall(MatSeqAIJRegister(MATSEQAIJCUSPARSE, MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 5449 #endif 5450 #if defined(PETSC_HAVE_HIP) 5451 PetscCall(MatSeqAIJRegister(MATSEQAIJHIPSPARSE, MatConvert_SeqAIJ_SeqAIJHIPSPARSE)); 5452 #endif 5453 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 5454 PetscCall(MatSeqAIJRegister(MATSEQAIJKOKKOS, MatConvert_SeqAIJ_SeqAIJKokkos)); 5455 #endif 5456 #if defined(PETSC_HAVE_VIENNACL) && defined(PETSC_HAVE_VIENNACL_NO_CUDA) 5457 PetscCall(MatSeqAIJRegister(MATMPIAIJVIENNACL, MatConvert_SeqAIJ_SeqAIJViennaCL)); 5458 #endif 5459 PetscFunctionReturn(PETSC_SUCCESS); 5460 } 5461 5462 /* 5463 Special version for direct calls from Fortran 5464 */ 5465 #include <petsc/private/fortranimpl.h> 5466 #if defined(PETSC_HAVE_FORTRAN_CAPS) 5467 #define matsetvaluesseqaij_ MATSETVALUESSEQAIJ 5468 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 5469 #define matsetvaluesseqaij_ matsetvaluesseqaij 5470 #endif 5471 5472 /* Change these macros so can be used in void function */ 5473 5474 /* Change these macros so can be used in void function */ 5475 /* Identical to PetscCallVoid, except it assigns to *_ierr */ 5476 #undef PetscCall 5477 #define PetscCall(...) \ 5478 do { \ 5479 PetscErrorCode ierr_msv_mpiaij = __VA_ARGS__; \ 5480 if (PetscUnlikely(ierr_msv_mpiaij)) { \ 5481 *_ierr = PetscError(PETSC_COMM_SELF, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr_msv_mpiaij, PETSC_ERROR_REPEAT, " "); \ 5482 return; \ 5483 } \ 5484 } while (0) 5485 5486 #undef SETERRQ 5487 #define SETERRQ(comm, ierr, ...) \ 5488 do { \ 5489 *_ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr, PETSC_ERROR_INITIAL, __VA_ARGS__); \ 5490 return; \ 5491 } while (0) 5492 5493 PETSC_EXTERN void matsetvaluesseqaij_(Mat *AA, PetscInt *mm, const PetscInt im[], PetscInt *nn, const PetscInt in[], const PetscScalar v[], InsertMode *isis, PetscErrorCode *_ierr) 5494 { 5495 Mat A = *AA; 5496 PetscInt m = *mm, n = *nn; 5497 InsertMode is = *isis; 5498 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5499 PetscInt *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N; 5500 PetscInt *imax, *ai, *ailen; 5501 PetscInt *aj, nonew = a->nonew, lastcol = -1; 5502 MatScalar *ap, value, *aa; 5503 PetscBool ignorezeroentries = a->ignorezeroentries; 5504 PetscBool roworiented = a->roworiented; 5505 5506 PetscFunctionBegin; 5507 MatCheckPreallocated(A, 1); 5508 imax = a->imax; 5509 ai = a->i; 5510 ailen = a->ilen; 5511 aj = a->j; 5512 aa = a->a; 5513 5514 for (k = 0; k < m; k++) { /* loop over added rows */ 5515 row = im[k]; 5516 if (row < 0) continue; 5517 PetscCheck(row < A->rmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large"); 5518 rp = aj + ai[row]; 5519 ap = aa + ai[row]; 5520 rmax = imax[row]; 5521 nrow = ailen[row]; 5522 low = 0; 5523 high = nrow; 5524 for (l = 0; l < n; l++) { /* loop over added columns */ 5525 if (in[l] < 0) continue; 5526 PetscCheck(in[l] < A->cmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Column too large"); 5527 col = in[l]; 5528 if (roworiented) value = v[l + k * n]; 5529 else value = v[k + l * m]; 5530 5531 if (value == 0.0 && ignorezeroentries && (is == ADD_VALUES)) continue; 5532 5533 if (col <= lastcol) low = 0; 5534 else high = nrow; 5535 lastcol = col; 5536 while (high - low > 5) { 5537 t = (low + high) / 2; 5538 if (rp[t] > col) high = t; 5539 else low = t; 5540 } 5541 for (i = low; i < high; i++) { 5542 if (rp[i] > col) break; 5543 if (rp[i] == col) { 5544 if (is == ADD_VALUES) ap[i] += value; 5545 else ap[i] = value; 5546 goto noinsert; 5547 } 5548 } 5549 if (value == 0.0 && ignorezeroentries) goto noinsert; 5550 if (nonew == 1) goto noinsert; 5551 PetscCheck(nonew != -1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero in the matrix"); 5552 MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar); 5553 N = nrow++ - 1; 5554 a->nz++; 5555 high++; 5556 /* shift up all the later entries in this row */ 5557 for (ii = N; ii >= i; ii--) { 5558 rp[ii + 1] = rp[ii]; 5559 ap[ii + 1] = ap[ii]; 5560 } 5561 rp[i] = col; 5562 ap[i] = value; 5563 A->nonzerostate++; 5564 noinsert:; 5565 low = i + 1; 5566 } 5567 ailen[row] = nrow; 5568 } 5569 PetscFunctionReturnVoid(); 5570 } 5571 /* Undefining these here since they were redefined from their original definition above! No 5572 * other PETSc functions should be defined past this point, as it is impossible to recover the 5573 * original definitions */ 5574 #undef PetscCall 5575 #undef SETERRQ 5576