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