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(PetscLayoutDestroy(&C->rmap)); 2705 PetscCall(PetscLayoutDestroy(&C->cmap)); 2706 PetscCall(PetscHeaderDestroy(&C)); 2707 } 2708 } else { 2709 PetscCall(MatDestroy(&C)); 2710 } 2711 } 2712 2713 /* Destroy Dummy submatrices created for reuse */ 2714 PetscCall(MatDestroySubMatrices_Dummy(n, mat)); 2715 2716 PetscCall(PetscFree(*mat)); 2717 PetscFunctionReturn(0); 2718 } 2719 2720 PetscErrorCode MatCreateSubMatrices_SeqAIJ(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *B[]) { 2721 PetscInt i; 2722 2723 PetscFunctionBegin; 2724 if (scall == MAT_INITIAL_MATRIX) PetscCall(PetscCalloc1(n + 1, B)); 2725 2726 for (i = 0; i < n; i++) PetscCall(MatCreateSubMatrix_SeqAIJ(A, irow[i], icol[i], PETSC_DECIDE, scall, &(*B)[i])); 2727 PetscFunctionReturn(0); 2728 } 2729 2730 PetscErrorCode MatIncreaseOverlap_SeqAIJ(Mat A, PetscInt is_max, IS is[], PetscInt ov) { 2731 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2732 PetscInt row, i, j, k, l, m, n, *nidx, isz, val; 2733 const PetscInt *idx; 2734 PetscInt start, end, *ai, *aj; 2735 PetscBT table; 2736 2737 PetscFunctionBegin; 2738 m = A->rmap->n; 2739 ai = a->i; 2740 aj = a->j; 2741 2742 PetscCheck(ov >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "illegal negative overlap value used"); 2743 2744 PetscCall(PetscMalloc1(m + 1, &nidx)); 2745 PetscCall(PetscBTCreate(m, &table)); 2746 2747 for (i = 0; i < is_max; i++) { 2748 /* Initialize the two local arrays */ 2749 isz = 0; 2750 PetscCall(PetscBTMemzero(m, table)); 2751 2752 /* Extract the indices, assume there can be duplicate entries */ 2753 PetscCall(ISGetIndices(is[i], &idx)); 2754 PetscCall(ISGetLocalSize(is[i], &n)); 2755 2756 /* Enter these into the temp arrays. I.e., mark table[row], enter row into new index */ 2757 for (j = 0; j < n; ++j) { 2758 if (!PetscBTLookupSet(table, idx[j])) nidx[isz++] = idx[j]; 2759 } 2760 PetscCall(ISRestoreIndices(is[i], &idx)); 2761 PetscCall(ISDestroy(&is[i])); 2762 2763 k = 0; 2764 for (j = 0; j < ov; j++) { /* for each overlap */ 2765 n = isz; 2766 for (; k < n; k++) { /* do only those rows in nidx[k], which are not done yet */ 2767 row = nidx[k]; 2768 start = ai[row]; 2769 end = ai[row + 1]; 2770 for (l = start; l < end; l++) { 2771 val = aj[l]; 2772 if (!PetscBTLookupSet(table, val)) nidx[isz++] = val; 2773 } 2774 } 2775 } 2776 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, isz, nidx, PETSC_COPY_VALUES, (is + i))); 2777 } 2778 PetscCall(PetscBTDestroy(&table)); 2779 PetscCall(PetscFree(nidx)); 2780 PetscFunctionReturn(0); 2781 } 2782 2783 /* -------------------------------------------------------------- */ 2784 PetscErrorCode MatPermute_SeqAIJ(Mat A, IS rowp, IS colp, Mat *B) { 2785 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2786 PetscInt i, nz = 0, m = A->rmap->n, n = A->cmap->n; 2787 const PetscInt *row, *col; 2788 PetscInt *cnew, j, *lens; 2789 IS icolp, irowp; 2790 PetscInt *cwork = NULL; 2791 PetscScalar *vwork = NULL; 2792 2793 PetscFunctionBegin; 2794 PetscCall(ISInvertPermutation(rowp, PETSC_DECIDE, &irowp)); 2795 PetscCall(ISGetIndices(irowp, &row)); 2796 PetscCall(ISInvertPermutation(colp, PETSC_DECIDE, &icolp)); 2797 PetscCall(ISGetIndices(icolp, &col)); 2798 2799 /* determine lengths of permuted rows */ 2800 PetscCall(PetscMalloc1(m + 1, &lens)); 2801 for (i = 0; i < m; i++) lens[row[i]] = a->i[i + 1] - a->i[i]; 2802 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 2803 PetscCall(MatSetSizes(*B, m, n, m, n)); 2804 PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 2805 PetscCall(MatSetType(*B, ((PetscObject)A)->type_name)); 2806 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*B, 0, lens)); 2807 PetscCall(PetscFree(lens)); 2808 2809 PetscCall(PetscMalloc1(n, &cnew)); 2810 for (i = 0; i < m; i++) { 2811 PetscCall(MatGetRow_SeqAIJ(A, i, &nz, &cwork, &vwork)); 2812 for (j = 0; j < nz; j++) cnew[j] = col[cwork[j]]; 2813 PetscCall(MatSetValues_SeqAIJ(*B, 1, &row[i], nz, cnew, vwork, INSERT_VALUES)); 2814 PetscCall(MatRestoreRow_SeqAIJ(A, i, &nz, &cwork, &vwork)); 2815 } 2816 PetscCall(PetscFree(cnew)); 2817 2818 (*B)->assembled = PETSC_FALSE; 2819 2820 #if defined(PETSC_HAVE_DEVICE) 2821 PetscCall(MatBindToCPU(*B, A->boundtocpu)); 2822 #endif 2823 PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 2824 PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 2825 PetscCall(ISRestoreIndices(irowp, &row)); 2826 PetscCall(ISRestoreIndices(icolp, &col)); 2827 PetscCall(ISDestroy(&irowp)); 2828 PetscCall(ISDestroy(&icolp)); 2829 if (rowp == colp) PetscCall(MatPropagateSymmetryOptions(A, *B)); 2830 PetscFunctionReturn(0); 2831 } 2832 2833 PetscErrorCode MatCopy_SeqAIJ(Mat A, Mat B, MatStructure str) { 2834 PetscFunctionBegin; 2835 /* If the two matrices have the same copy implementation, use fast copy. */ 2836 if (str == SAME_NONZERO_PATTERN && (A->ops->copy == B->ops->copy)) { 2837 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2838 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 2839 const PetscScalar *aa; 2840 2841 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 2842 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]); 2843 PetscCall(PetscArraycpy(b->a, aa, a->i[A->rmap->n])); 2844 PetscCall(PetscObjectStateIncrease((PetscObject)B)); 2845 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 2846 } else { 2847 PetscCall(MatCopy_Basic(A, B, str)); 2848 } 2849 PetscFunctionReturn(0); 2850 } 2851 2852 PetscErrorCode MatSetUp_SeqAIJ(Mat A) { 2853 PetscFunctionBegin; 2854 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(A, PETSC_DEFAULT, NULL)); 2855 PetscFunctionReturn(0); 2856 } 2857 2858 PETSC_INTERN PetscErrorCode MatSeqAIJGetArray_SeqAIJ(Mat A, PetscScalar *array[]) { 2859 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2860 2861 PetscFunctionBegin; 2862 *array = a->a; 2863 PetscFunctionReturn(0); 2864 } 2865 2866 PETSC_INTERN PetscErrorCode MatSeqAIJRestoreArray_SeqAIJ(Mat A, PetscScalar *array[]) { 2867 PetscFunctionBegin; 2868 *array = NULL; 2869 PetscFunctionReturn(0); 2870 } 2871 2872 /* 2873 Computes the number of nonzeros per row needed for preallocation when X and Y 2874 have different nonzero structure. 2875 */ 2876 PetscErrorCode MatAXPYGetPreallocation_SeqX_private(PetscInt m, const PetscInt *xi, const PetscInt *xj, const PetscInt *yi, const PetscInt *yj, PetscInt *nnz) { 2877 PetscInt i, j, k, nzx, nzy; 2878 2879 PetscFunctionBegin; 2880 /* Set the number of nonzeros in the new matrix */ 2881 for (i = 0; i < m; i++) { 2882 const PetscInt *xjj = xj + xi[i], *yjj = yj + yi[i]; 2883 nzx = xi[i + 1] - xi[i]; 2884 nzy = yi[i + 1] - yi[i]; 2885 nnz[i] = 0; 2886 for (j = 0, k = 0; j < nzx; j++) { /* Point in X */ 2887 for (; k < nzy && yjj[k] < xjj[j]; k++) nnz[i]++; /* Catch up to X */ 2888 if (k < nzy && yjj[k] == xjj[j]) k++; /* Skip duplicate */ 2889 nnz[i]++; 2890 } 2891 for (; k < nzy; k++) nnz[i]++; 2892 } 2893 PetscFunctionReturn(0); 2894 } 2895 2896 PetscErrorCode MatAXPYGetPreallocation_SeqAIJ(Mat Y, Mat X, PetscInt *nnz) { 2897 PetscInt m = Y->rmap->N; 2898 Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data; 2899 Mat_SeqAIJ *y = (Mat_SeqAIJ *)Y->data; 2900 2901 PetscFunctionBegin; 2902 /* Set the number of nonzeros in the new matrix */ 2903 PetscCall(MatAXPYGetPreallocation_SeqX_private(m, x->i, x->j, y->i, y->j, nnz)); 2904 PetscFunctionReturn(0); 2905 } 2906 2907 PetscErrorCode MatAXPY_SeqAIJ(Mat Y, PetscScalar a, Mat X, MatStructure str) { 2908 Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data, *y = (Mat_SeqAIJ *)Y->data; 2909 2910 PetscFunctionBegin; 2911 if (str == UNKNOWN_NONZERO_PATTERN || (PetscDefined(USE_DEBUG) && str == SAME_NONZERO_PATTERN)) { 2912 PetscBool e = x->nz == y->nz ? PETSC_TRUE : PETSC_FALSE; 2913 if (e) { 2914 PetscCall(PetscArraycmp(x->i, y->i, Y->rmap->n + 1, &e)); 2915 if (e) { 2916 PetscCall(PetscArraycmp(x->j, y->j, y->nz, &e)); 2917 if (e) str = SAME_NONZERO_PATTERN; 2918 } 2919 } 2920 if (!e) PetscCheck(str != SAME_NONZERO_PATTERN, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatStructure is not SAME_NONZERO_PATTERN"); 2921 } 2922 if (str == SAME_NONZERO_PATTERN) { 2923 const PetscScalar *xa; 2924 PetscScalar *ya, alpha = a; 2925 PetscBLASInt one = 1, bnz; 2926 2927 PetscCall(PetscBLASIntCast(x->nz, &bnz)); 2928 PetscCall(MatSeqAIJGetArray(Y, &ya)); 2929 PetscCall(MatSeqAIJGetArrayRead(X, &xa)); 2930 PetscCallBLAS("BLASaxpy", BLASaxpy_(&bnz, &alpha, xa, &one, ya, &one)); 2931 PetscCall(MatSeqAIJRestoreArrayRead(X, &xa)); 2932 PetscCall(MatSeqAIJRestoreArray(Y, &ya)); 2933 PetscCall(PetscLogFlops(2.0 * bnz)); 2934 PetscCall(MatSeqAIJInvalidateDiagonal(Y)); 2935 PetscCall(PetscObjectStateIncrease((PetscObject)Y)); 2936 } else if (str == SUBSET_NONZERO_PATTERN) { /* nonzeros of X is a subset of Y's */ 2937 PetscCall(MatAXPY_Basic(Y, a, X, str)); 2938 } else { 2939 Mat B; 2940 PetscInt *nnz; 2941 PetscCall(PetscMalloc1(Y->rmap->N, &nnz)); 2942 PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &B)); 2943 PetscCall(PetscObjectSetName((PetscObject)B, ((PetscObject)Y)->name)); 2944 PetscCall(MatSetLayouts(B, Y->rmap, Y->cmap)); 2945 PetscCall(MatSetType(B, ((PetscObject)Y)->type_name)); 2946 PetscCall(MatAXPYGetPreallocation_SeqAIJ(Y, X, nnz)); 2947 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 2948 PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str)); 2949 PetscCall(MatHeaderMerge(Y, &B)); 2950 PetscCall(MatSeqAIJCheckInode(Y)); 2951 PetscCall(PetscFree(nnz)); 2952 } 2953 PetscFunctionReturn(0); 2954 } 2955 2956 PETSC_INTERN PetscErrorCode MatConjugate_SeqAIJ(Mat mat) { 2957 #if defined(PETSC_USE_COMPLEX) 2958 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 2959 PetscInt i, nz; 2960 PetscScalar *a; 2961 2962 PetscFunctionBegin; 2963 nz = aij->nz; 2964 PetscCall(MatSeqAIJGetArray(mat, &a)); 2965 for (i = 0; i < nz; i++) a[i] = PetscConj(a[i]); 2966 PetscCall(MatSeqAIJRestoreArray(mat, &a)); 2967 #else 2968 PetscFunctionBegin; 2969 #endif 2970 PetscFunctionReturn(0); 2971 } 2972 2973 PetscErrorCode MatGetRowMaxAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) { 2974 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 2975 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 2976 PetscReal atmp; 2977 PetscScalar *x; 2978 const MatScalar *aa, *av; 2979 2980 PetscFunctionBegin; 2981 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 2982 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 2983 aa = av; 2984 ai = a->i; 2985 aj = a->j; 2986 2987 PetscCall(VecSet(v, 0.0)); 2988 PetscCall(VecGetArrayWrite(v, &x)); 2989 PetscCall(VecGetLocalSize(v, &n)); 2990 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 2991 for (i = 0; i < m; i++) { 2992 ncols = ai[1] - ai[0]; 2993 ai++; 2994 for (j = 0; j < ncols; j++) { 2995 atmp = PetscAbsScalar(*aa); 2996 if (PetscAbsScalar(x[i]) < atmp) { 2997 x[i] = atmp; 2998 if (idx) idx[i] = *aj; 2999 } 3000 aa++; 3001 aj++; 3002 } 3003 } 3004 PetscCall(VecRestoreArrayWrite(v, &x)); 3005 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3006 PetscFunctionReturn(0); 3007 } 3008 3009 PetscErrorCode MatGetRowMax_SeqAIJ(Mat A, Vec v, PetscInt idx[]) { 3010 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3011 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3012 PetscScalar *x; 3013 const MatScalar *aa, *av; 3014 3015 PetscFunctionBegin; 3016 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3017 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3018 aa = av; 3019 ai = a->i; 3020 aj = a->j; 3021 3022 PetscCall(VecSet(v, 0.0)); 3023 PetscCall(VecGetArrayWrite(v, &x)); 3024 PetscCall(VecGetLocalSize(v, &n)); 3025 PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3026 for (i = 0; i < m; i++) { 3027 ncols = ai[1] - ai[0]; 3028 ai++; 3029 if (ncols == A->cmap->n) { /* row is dense */ 3030 x[i] = *aa; 3031 if (idx) idx[i] = 0; 3032 } else { /* row is sparse so already KNOW maximum is 0.0 or higher */ 3033 x[i] = 0.0; 3034 if (idx) { 3035 for (j = 0; j < ncols; j++) { /* find first implicit 0.0 in the row */ 3036 if (aj[j] > j) { 3037 idx[i] = j; 3038 break; 3039 } 3040 } 3041 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3042 if (j == ncols && j < A->cmap->n) idx[i] = j; 3043 } 3044 } 3045 for (j = 0; j < ncols; j++) { 3046 if (PetscRealPart(x[i]) < PetscRealPart(*aa)) { 3047 x[i] = *aa; 3048 if (idx) idx[i] = *aj; 3049 } 3050 aa++; 3051 aj++; 3052 } 3053 } 3054 PetscCall(VecRestoreArrayWrite(v, &x)); 3055 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3056 PetscFunctionReturn(0); 3057 } 3058 3059 PetscErrorCode MatGetRowMinAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) { 3060 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3061 PetscInt i, j, m = A->rmap->n, *ai, *aj, ncols, n; 3062 PetscScalar *x; 3063 const MatScalar *aa, *av; 3064 3065 PetscFunctionBegin; 3066 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3067 aa = av; 3068 ai = a->i; 3069 aj = a->j; 3070 3071 PetscCall(VecSet(v, 0.0)); 3072 PetscCall(VecGetArrayWrite(v, &x)); 3073 PetscCall(VecGetLocalSize(v, &n)); 3074 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector, %" PetscInt_FMT " vs. %" PetscInt_FMT " rows", m, n); 3075 for (i = 0; i < m; i++) { 3076 ncols = ai[1] - ai[0]; 3077 ai++; 3078 if (ncols == A->cmap->n) { /* row is dense */ 3079 x[i] = *aa; 3080 if (idx) idx[i] = 0; 3081 } else { /* row is sparse so already KNOW minimum is 0.0 or higher */ 3082 x[i] = 0.0; 3083 if (idx) { /* find first implicit 0.0 in the row */ 3084 for (j = 0; j < ncols; j++) { 3085 if (aj[j] > j) { 3086 idx[i] = j; 3087 break; 3088 } 3089 } 3090 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3091 if (j == ncols && j < A->cmap->n) idx[i] = j; 3092 } 3093 } 3094 for (j = 0; j < ncols; j++) { 3095 if (PetscAbsScalar(x[i]) > PetscAbsScalar(*aa)) { 3096 x[i] = *aa; 3097 if (idx) idx[i] = *aj; 3098 } 3099 aa++; 3100 aj++; 3101 } 3102 } 3103 PetscCall(VecRestoreArrayWrite(v, &x)); 3104 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3105 PetscFunctionReturn(0); 3106 } 3107 3108 PetscErrorCode MatGetRowMin_SeqAIJ(Mat A, Vec v, PetscInt idx[]) { 3109 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3110 PetscInt i, j, m = A->rmap->n, ncols, n; 3111 const PetscInt *ai, *aj; 3112 PetscScalar *x; 3113 const MatScalar *aa, *av; 3114 3115 PetscFunctionBegin; 3116 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3117 PetscCall(MatSeqAIJGetArrayRead(A, &av)); 3118 aa = av; 3119 ai = a->i; 3120 aj = a->j; 3121 3122 PetscCall(VecSet(v, 0.0)); 3123 PetscCall(VecGetArrayWrite(v, &x)); 3124 PetscCall(VecGetLocalSize(v, &n)); 3125 PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector"); 3126 for (i = 0; i < m; i++) { 3127 ncols = ai[1] - ai[0]; 3128 ai++; 3129 if (ncols == A->cmap->n) { /* row is dense */ 3130 x[i] = *aa; 3131 if (idx) idx[i] = 0; 3132 } else { /* row is sparse so already KNOW minimum is 0.0 or lower */ 3133 x[i] = 0.0; 3134 if (idx) { /* find first implicit 0.0 in the row */ 3135 for (j = 0; j < ncols; j++) { 3136 if (aj[j] > j) { 3137 idx[i] = j; 3138 break; 3139 } 3140 } 3141 /* in case first implicit 0.0 in the row occurs at ncols-th column */ 3142 if (j == ncols && j < A->cmap->n) idx[i] = j; 3143 } 3144 } 3145 for (j = 0; j < ncols; j++) { 3146 if (PetscRealPart(x[i]) > PetscRealPart(*aa)) { 3147 x[i] = *aa; 3148 if (idx) idx[i] = *aj; 3149 } 3150 aa++; 3151 aj++; 3152 } 3153 } 3154 PetscCall(VecRestoreArrayWrite(v, &x)); 3155 PetscCall(MatSeqAIJRestoreArrayRead(A, &av)); 3156 PetscFunctionReturn(0); 3157 } 3158 3159 PetscErrorCode MatInvertBlockDiagonal_SeqAIJ(Mat A, const PetscScalar **values) { 3160 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 3161 PetscInt i, bs = PetscAbs(A->rmap->bs), mbs = A->rmap->n / bs, ipvt[5], bs2 = bs * bs, *v_pivots, ij[7], *IJ, j; 3162 MatScalar *diag, work[25], *v_work; 3163 const PetscReal shift = 0.0; 3164 PetscBool allowzeropivot, zeropivotdetected = PETSC_FALSE; 3165 3166 PetscFunctionBegin; 3167 allowzeropivot = PetscNot(A->erroriffailure); 3168 if (a->ibdiagvalid) { 3169 if (values) *values = a->ibdiag; 3170 PetscFunctionReturn(0); 3171 } 3172 PetscCall(MatMarkDiagonal_SeqAIJ(A)); 3173 if (!a->ibdiag) { 3174 PetscCall(PetscMalloc1(bs2 * mbs, &a->ibdiag)); 3175 PetscCall(PetscLogObjectMemory((PetscObject)A, bs2 * mbs * sizeof(PetscScalar))); 3176 } 3177 diag = a->ibdiag; 3178 if (values) *values = a->ibdiag; 3179 /* factor and invert each block */ 3180 switch (bs) { 3181 case 1: 3182 for (i = 0; i < mbs; i++) { 3183 PetscCall(MatGetValues(A, 1, &i, 1, &i, diag + i)); 3184 if (PetscAbsScalar(diag[i] + shift) < PETSC_MACHINE_EPSILON) { 3185 if (allowzeropivot) { 3186 A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3187 A->factorerror_zeropivot_value = PetscAbsScalar(diag[i]); 3188 A->factorerror_zeropivot_row = i; 3189 PetscCall(PetscInfo(A, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g\n", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON)); 3190 } 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); 3191 } 3192 diag[i] = (PetscScalar)1.0 / (diag[i] + shift); 3193 } 3194 break; 3195 case 2: 3196 for (i = 0; i < mbs; i++) { 3197 ij[0] = 2 * i; 3198 ij[1] = 2 * i + 1; 3199 PetscCall(MatGetValues(A, 2, ij, 2, ij, diag)); 3200 PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected)); 3201 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3202 PetscCall(PetscKernel_A_gets_transpose_A_2(diag)); 3203 diag += 4; 3204 } 3205 break; 3206 case 3: 3207 for (i = 0; i < mbs; i++) { 3208 ij[0] = 3 * i; 3209 ij[1] = 3 * i + 1; 3210 ij[2] = 3 * i + 2; 3211 PetscCall(MatGetValues(A, 3, ij, 3, ij, diag)); 3212 PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected)); 3213 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3214 PetscCall(PetscKernel_A_gets_transpose_A_3(diag)); 3215 diag += 9; 3216 } 3217 break; 3218 case 4: 3219 for (i = 0; i < mbs; i++) { 3220 ij[0] = 4 * i; 3221 ij[1] = 4 * i + 1; 3222 ij[2] = 4 * i + 2; 3223 ij[3] = 4 * i + 3; 3224 PetscCall(MatGetValues(A, 4, ij, 4, ij, diag)); 3225 PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected)); 3226 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3227 PetscCall(PetscKernel_A_gets_transpose_A_4(diag)); 3228 diag += 16; 3229 } 3230 break; 3231 case 5: 3232 for (i = 0; i < mbs; i++) { 3233 ij[0] = 5 * i; 3234 ij[1] = 5 * i + 1; 3235 ij[2] = 5 * i + 2; 3236 ij[3] = 5 * i + 3; 3237 ij[4] = 5 * i + 4; 3238 PetscCall(MatGetValues(A, 5, ij, 5, ij, diag)); 3239 PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected)); 3240 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3241 PetscCall(PetscKernel_A_gets_transpose_A_5(diag)); 3242 diag += 25; 3243 } 3244 break; 3245 case 6: 3246 for (i = 0; i < mbs; i++) { 3247 ij[0] = 6 * i; 3248 ij[1] = 6 * i + 1; 3249 ij[2] = 6 * i + 2; 3250 ij[3] = 6 * i + 3; 3251 ij[4] = 6 * i + 4; 3252 ij[5] = 6 * i + 5; 3253 PetscCall(MatGetValues(A, 6, ij, 6, ij, diag)); 3254 PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected)); 3255 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3256 PetscCall(PetscKernel_A_gets_transpose_A_6(diag)); 3257 diag += 36; 3258 } 3259 break; 3260 case 7: 3261 for (i = 0; i < mbs; i++) { 3262 ij[0] = 7 * i; 3263 ij[1] = 7 * i + 1; 3264 ij[2] = 7 * i + 2; 3265 ij[3] = 7 * i + 3; 3266 ij[4] = 7 * i + 4; 3267 ij[5] = 7 * i + 5; 3268 ij[5] = 7 * i + 6; 3269 PetscCall(MatGetValues(A, 7, ij, 7, ij, diag)); 3270 PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected)); 3271 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3272 PetscCall(PetscKernel_A_gets_transpose_A_7(diag)); 3273 diag += 49; 3274 } 3275 break; 3276 default: 3277 PetscCall(PetscMalloc3(bs, &v_work, bs, &v_pivots, bs, &IJ)); 3278 for (i = 0; i < mbs; i++) { 3279 for (j = 0; j < bs; j++) IJ[j] = bs * i + j; 3280 PetscCall(MatGetValues(A, bs, IJ, bs, IJ, diag)); 3281 PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected)); 3282 if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT; 3283 PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bs)); 3284 diag += bs2; 3285 } 3286 PetscCall(PetscFree3(v_work, v_pivots, IJ)); 3287 } 3288 a->ibdiagvalid = PETSC_TRUE; 3289 PetscFunctionReturn(0); 3290 } 3291 3292 static PetscErrorCode MatSetRandom_SeqAIJ(Mat x, PetscRandom rctx) { 3293 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3294 PetscScalar a, *aa; 3295 PetscInt m, n, i, j, col; 3296 3297 PetscFunctionBegin; 3298 if (!x->assembled) { 3299 PetscCall(MatGetSize(x, &m, &n)); 3300 for (i = 0; i < m; i++) { 3301 for (j = 0; j < aij->imax[i]; j++) { 3302 PetscCall(PetscRandomGetValue(rctx, &a)); 3303 col = (PetscInt)(n * PetscRealPart(a)); 3304 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3305 } 3306 } 3307 } else { 3308 PetscCall(MatSeqAIJGetArrayWrite(x, &aa)); 3309 for (i = 0; i < aij->nz; i++) PetscCall(PetscRandomGetValue(rctx, aa + i)); 3310 PetscCall(MatSeqAIJRestoreArrayWrite(x, &aa)); 3311 } 3312 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3313 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3314 PetscFunctionReturn(0); 3315 } 3316 3317 /* Like MatSetRandom_SeqAIJ, but do not set values on columns in range of [low, high) */ 3318 PetscErrorCode MatSetRandomSkipColumnRange_SeqAIJ_Private(Mat x, PetscInt low, PetscInt high, PetscRandom rctx) { 3319 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data; 3320 PetscScalar a; 3321 PetscInt m, n, i, j, col, nskip; 3322 3323 PetscFunctionBegin; 3324 nskip = high - low; 3325 PetscCall(MatGetSize(x, &m, &n)); 3326 n -= nskip; /* shrink number of columns where nonzeros can be set */ 3327 for (i = 0; i < m; i++) { 3328 for (j = 0; j < aij->imax[i]; j++) { 3329 PetscCall(PetscRandomGetValue(rctx, &a)); 3330 col = (PetscInt)(n * PetscRealPart(a)); 3331 if (col >= low) col += nskip; /* shift col rightward to skip the hole */ 3332 PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES)); 3333 } 3334 } 3335 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 3336 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 3337 PetscFunctionReturn(0); 3338 } 3339 3340 /* -------------------------------------------------------------------*/ 3341 static struct _MatOps MatOps_Values = {MatSetValues_SeqAIJ, 3342 MatGetRow_SeqAIJ, 3343 MatRestoreRow_SeqAIJ, 3344 MatMult_SeqAIJ, 3345 /* 4*/ MatMultAdd_SeqAIJ, 3346 MatMultTranspose_SeqAIJ, 3347 MatMultTransposeAdd_SeqAIJ, 3348 NULL, 3349 NULL, 3350 NULL, 3351 /* 10*/ NULL, 3352 MatLUFactor_SeqAIJ, 3353 NULL, 3354 MatSOR_SeqAIJ, 3355 MatTranspose_SeqAIJ, 3356 /*1 5*/ MatGetInfo_SeqAIJ, 3357 MatEqual_SeqAIJ, 3358 MatGetDiagonal_SeqAIJ, 3359 MatDiagonalScale_SeqAIJ, 3360 MatNorm_SeqAIJ, 3361 /* 20*/ NULL, 3362 MatAssemblyEnd_SeqAIJ, 3363 MatSetOption_SeqAIJ, 3364 MatZeroEntries_SeqAIJ, 3365 /* 24*/ MatZeroRows_SeqAIJ, 3366 NULL, 3367 NULL, 3368 NULL, 3369 NULL, 3370 /* 29*/ MatSetUp_SeqAIJ, 3371 NULL, 3372 NULL, 3373 NULL, 3374 NULL, 3375 /* 34*/ MatDuplicate_SeqAIJ, 3376 NULL, 3377 NULL, 3378 MatILUFactor_SeqAIJ, 3379 NULL, 3380 /* 39*/ MatAXPY_SeqAIJ, 3381 MatCreateSubMatrices_SeqAIJ, 3382 MatIncreaseOverlap_SeqAIJ, 3383 MatGetValues_SeqAIJ, 3384 MatCopy_SeqAIJ, 3385 /* 44*/ MatGetRowMax_SeqAIJ, 3386 MatScale_SeqAIJ, 3387 MatShift_SeqAIJ, 3388 MatDiagonalSet_SeqAIJ, 3389 MatZeroRowsColumns_SeqAIJ, 3390 /* 49*/ MatSetRandom_SeqAIJ, 3391 MatGetRowIJ_SeqAIJ, 3392 MatRestoreRowIJ_SeqAIJ, 3393 MatGetColumnIJ_SeqAIJ, 3394 MatRestoreColumnIJ_SeqAIJ, 3395 /* 54*/ MatFDColoringCreate_SeqXAIJ, 3396 NULL, 3397 NULL, 3398 MatPermute_SeqAIJ, 3399 NULL, 3400 /* 59*/ NULL, 3401 MatDestroy_SeqAIJ, 3402 MatView_SeqAIJ, 3403 NULL, 3404 NULL, 3405 /* 64*/ NULL, 3406 MatMatMatMultNumeric_SeqAIJ_SeqAIJ_SeqAIJ, 3407 NULL, 3408 NULL, 3409 NULL, 3410 /* 69*/ MatGetRowMaxAbs_SeqAIJ, 3411 MatGetRowMinAbs_SeqAIJ, 3412 NULL, 3413 NULL, 3414 NULL, 3415 /* 74*/ NULL, 3416 MatFDColoringApply_AIJ, 3417 NULL, 3418 NULL, 3419 NULL, 3420 /* 79*/ MatFindZeroDiagonals_SeqAIJ, 3421 NULL, 3422 NULL, 3423 NULL, 3424 MatLoad_SeqAIJ, 3425 /* 84*/ MatIsSymmetric_SeqAIJ, 3426 MatIsHermitian_SeqAIJ, 3427 NULL, 3428 NULL, 3429 NULL, 3430 /* 89*/ NULL, 3431 NULL, 3432 MatMatMultNumeric_SeqAIJ_SeqAIJ, 3433 NULL, 3434 NULL, 3435 /* 94*/ MatPtAPNumeric_SeqAIJ_SeqAIJ_SparseAxpy, 3436 NULL, 3437 NULL, 3438 MatMatTransposeMultNumeric_SeqAIJ_SeqAIJ, 3439 NULL, 3440 /* 99*/ MatProductSetFromOptions_SeqAIJ, 3441 NULL, 3442 NULL, 3443 MatConjugate_SeqAIJ, 3444 NULL, 3445 /*104*/ MatSetValuesRow_SeqAIJ, 3446 MatRealPart_SeqAIJ, 3447 MatImaginaryPart_SeqAIJ, 3448 NULL, 3449 NULL, 3450 /*109*/ MatMatSolve_SeqAIJ, 3451 NULL, 3452 MatGetRowMin_SeqAIJ, 3453 NULL, 3454 MatMissingDiagonal_SeqAIJ, 3455 /*114*/ NULL, 3456 NULL, 3457 NULL, 3458 NULL, 3459 NULL, 3460 /*119*/ NULL, 3461 NULL, 3462 NULL, 3463 NULL, 3464 MatGetMultiProcBlock_SeqAIJ, 3465 /*124*/ MatFindNonzeroRows_SeqAIJ, 3466 MatGetColumnReductions_SeqAIJ, 3467 MatInvertBlockDiagonal_SeqAIJ, 3468 MatInvertVariableBlockDiagonal_SeqAIJ, 3469 NULL, 3470 /*129*/ NULL, 3471 NULL, 3472 NULL, 3473 MatTransposeMatMultNumeric_SeqAIJ_SeqAIJ, 3474 MatTransposeColoringCreate_SeqAIJ, 3475 /*134*/ MatTransColoringApplySpToDen_SeqAIJ, 3476 MatTransColoringApplyDenToSp_SeqAIJ, 3477 NULL, 3478 NULL, 3479 MatRARtNumeric_SeqAIJ_SeqAIJ, 3480 /*139*/ NULL, 3481 NULL, 3482 NULL, 3483 MatFDColoringSetUp_SeqXAIJ, 3484 MatFindOffBlockDiagonalEntries_SeqAIJ, 3485 MatCreateMPIMatConcatenateSeqMat_SeqAIJ, 3486 /*145*/ MatDestroySubMatrices_SeqAIJ, 3487 NULL, 3488 NULL, 3489 MatCreateGraph_Simple_AIJ, 3490 MatFilter_AIJ, 3491 /*150*/ MatTransposeSymbolic_SeqAIJ}; 3492 3493 PetscErrorCode MatSeqAIJSetColumnIndices_SeqAIJ(Mat mat, PetscInt *indices) { 3494 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3495 PetscInt i, nz, n; 3496 3497 PetscFunctionBegin; 3498 nz = aij->maxnz; 3499 n = mat->rmap->n; 3500 for (i = 0; i < nz; i++) aij->j[i] = indices[i]; 3501 aij->nz = nz; 3502 for (i = 0; i < n; i++) aij->ilen[i] = aij->imax[i]; 3503 PetscFunctionReturn(0); 3504 } 3505 3506 /* 3507 * Given a sparse matrix with global column indices, compact it by using a local column space. 3508 * The result matrix helps saving memory in other algorithms, such as MatPtAPSymbolic_MPIAIJ_MPIAIJ_scalable() 3509 */ 3510 PetscErrorCode MatSeqAIJCompactOutExtraColumns_SeqAIJ(Mat mat, ISLocalToGlobalMapping *mapping) { 3511 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3512 PetscTable gid1_lid1; 3513 PetscTablePosition tpos; 3514 PetscInt gid, lid, i, ec, nz = aij->nz; 3515 PetscInt *garray, *jj = aij->j; 3516 3517 PetscFunctionBegin; 3518 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3519 PetscValidPointer(mapping, 2); 3520 /* use a table */ 3521 PetscCall(PetscTableCreate(mat->rmap->n, mat->cmap->N + 1, &gid1_lid1)); 3522 ec = 0; 3523 for (i = 0; i < nz; i++) { 3524 PetscInt data, gid1 = jj[i] + 1; 3525 PetscCall(PetscTableFind(gid1_lid1, gid1, &data)); 3526 if (!data) { 3527 /* one based table */ 3528 PetscCall(PetscTableAdd(gid1_lid1, gid1, ++ec, INSERT_VALUES)); 3529 } 3530 } 3531 /* form array of columns we need */ 3532 PetscCall(PetscMalloc1(ec, &garray)); 3533 PetscCall(PetscTableGetHeadPosition(gid1_lid1, &tpos)); 3534 while (tpos) { 3535 PetscCall(PetscTableGetNext(gid1_lid1, &tpos, &gid, &lid)); 3536 gid--; 3537 lid--; 3538 garray[lid] = gid; 3539 } 3540 PetscCall(PetscSortInt(ec, garray)); /* sort, and rebuild */ 3541 PetscCall(PetscTableRemoveAll(gid1_lid1)); 3542 for (i = 0; i < ec; i++) PetscCall(PetscTableAdd(gid1_lid1, garray[i] + 1, i + 1, INSERT_VALUES)); 3543 /* compact out the extra columns in B */ 3544 for (i = 0; i < nz; i++) { 3545 PetscInt gid1 = jj[i] + 1; 3546 PetscCall(PetscTableFind(gid1_lid1, gid1, &lid)); 3547 lid--; 3548 jj[i] = lid; 3549 } 3550 PetscCall(PetscLayoutDestroy(&mat->cmap)); 3551 PetscCall(PetscTableDestroy(&gid1_lid1)); 3552 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)mat), ec, ec, 1, &mat->cmap)); 3553 PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, mat->cmap->bs, mat->cmap->n, garray, PETSC_OWN_POINTER, mapping)); 3554 PetscCall(ISLocalToGlobalMappingSetType(*mapping, ISLOCALTOGLOBALMAPPINGHASH)); 3555 PetscFunctionReturn(0); 3556 } 3557 3558 /*@ 3559 MatSeqAIJSetColumnIndices - Set the column indices for all the rows 3560 in the matrix. 3561 3562 Input Parameters: 3563 + mat - the `MATSEQAIJ` matrix 3564 - indices - the column indices 3565 3566 Level: advanced 3567 3568 Notes: 3569 This can be called if you have precomputed the nonzero structure of the 3570 matrix and want to provide it to the matrix object to improve the performance 3571 of the `MatSetValues()` operation. 3572 3573 You MUST have set the correct numbers of nonzeros per row in the call to 3574 `MatCreateSeqAIJ()`, and the columns indices MUST be sorted. 3575 3576 MUST be called before any calls to `MatSetValues()` 3577 3578 The indices should start with zero, not one. 3579 3580 @*/ 3581 PetscErrorCode MatSeqAIJSetColumnIndices(Mat mat, PetscInt *indices) { 3582 PetscFunctionBegin; 3583 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3584 PetscValidIntPointer(indices, 2); 3585 PetscUseMethod(mat, "MatSeqAIJSetColumnIndices_C", (Mat, PetscInt *), (mat, indices)); 3586 PetscFunctionReturn(0); 3587 } 3588 3589 /* ----------------------------------------------------------------------------------------*/ 3590 3591 PetscErrorCode MatStoreValues_SeqAIJ(Mat mat) { 3592 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3593 size_t nz = aij->i[mat->rmap->n]; 3594 3595 PetscFunctionBegin; 3596 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3597 3598 /* allocate space for values if not already there */ 3599 if (!aij->saved_values) { 3600 PetscCall(PetscMalloc1(nz + 1, &aij->saved_values)); 3601 PetscCall(PetscLogObjectMemory((PetscObject)mat, (nz + 1) * sizeof(PetscScalar))); 3602 } 3603 3604 /* copy values over */ 3605 PetscCall(PetscArraycpy(aij->saved_values, aij->a, nz)); 3606 PetscFunctionReturn(0); 3607 } 3608 3609 /*@ 3610 MatStoreValues - Stashes a copy of the matrix values; this allows, for 3611 example, reuse of the linear part of a Jacobian, while recomputing the 3612 nonlinear portion. 3613 3614 Collect on mat 3615 3616 Input Parameters: 3617 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3618 3619 Level: advanced 3620 3621 Common Usage, with `SNESSolve()`: 3622 $ Create Jacobian matrix 3623 $ Set linear terms into matrix 3624 $ Apply boundary conditions to matrix, at this time matrix must have 3625 $ final nonzero structure (i.e. setting the nonlinear terms and applying 3626 $ boundary conditions again will not change the nonzero structure 3627 $ ierr = MatSetOption(mat,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE); 3628 $ ierr = MatStoreValues(mat); 3629 $ Call SNESSetJacobian() with matrix 3630 $ In your Jacobian routine 3631 $ ierr = MatRetrieveValues(mat); 3632 $ Set nonlinear terms in matrix 3633 3634 Common Usage without SNESSolve(), i.e. when you handle nonlinear solve yourself: 3635 $ // build linear portion of Jacobian 3636 $ ierr = MatSetOption(mat,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE); 3637 $ ierr = MatStoreValues(mat); 3638 $ loop over nonlinear iterations 3639 $ ierr = MatRetrieveValues(mat); 3640 $ // call MatSetValues(mat,...) to set nonliner portion of Jacobian 3641 $ // call MatAssemblyBegin/End() on matrix 3642 $ Solve linear system with Jacobian 3643 $ endloop 3644 3645 Notes: 3646 Matrix must already be assemblied before calling this routine 3647 Must set the matrix option `MatSetOption`(mat,`MAT_NEW_NONZERO_LOCATIONS`,`PETSC_FALSE`); before 3648 calling this routine. 3649 3650 When this is called multiple times it overwrites the previous set of stored values 3651 and does not allocated additional space. 3652 3653 .seealso: `MatRetrieveValues()` 3654 @*/ 3655 PetscErrorCode MatStoreValues(Mat mat) { 3656 PetscFunctionBegin; 3657 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3658 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3659 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3660 PetscUseMethod(mat, "MatStoreValues_C", (Mat), (mat)); 3661 PetscFunctionReturn(0); 3662 } 3663 3664 PetscErrorCode MatRetrieveValues_SeqAIJ(Mat mat) { 3665 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 3666 PetscInt nz = aij->i[mat->rmap->n]; 3667 3668 PetscFunctionBegin; 3669 PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first"); 3670 PetscCheck(aij->saved_values, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatStoreValues(A);first"); 3671 /* copy values over */ 3672 PetscCall(PetscArraycpy(aij->a, aij->saved_values, nz)); 3673 PetscFunctionReturn(0); 3674 } 3675 3676 /*@ 3677 MatRetrieveValues - Retrieves the copy of the matrix values; this allows, for 3678 example, reuse of the linear part of a Jacobian, while recomputing the 3679 nonlinear portion. 3680 3681 Collect on mat 3682 3683 Input Parameters: 3684 . mat - the matrix (currently only `MATAIJ` matrices support this option) 3685 3686 Level: advanced 3687 3688 .seealso: `MatStoreValues()` 3689 @*/ 3690 PetscErrorCode MatRetrieveValues(Mat mat) { 3691 PetscFunctionBegin; 3692 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3693 PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 3694 PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 3695 PetscUseMethod(mat, "MatRetrieveValues_C", (Mat), (mat)); 3696 PetscFunctionReturn(0); 3697 } 3698 3699 /* --------------------------------------------------------------------------------*/ 3700 /*@C 3701 MatCreateSeqAIJ - Creates a sparse matrix in `MATSEQAIJ` (compressed row) format 3702 (the default parallel PETSc format). For good matrix assembly performance 3703 the user should preallocate the matrix storage by setting the parameter nz 3704 (or the array nnz). By setting these parameters accurately, performance 3705 during matrix assembly can be increased by more than a factor of 50. 3706 3707 Collective 3708 3709 Input Parameters: 3710 + comm - MPI communicator, set to `PETSC_COMM_SELF` 3711 . m - number of rows 3712 . n - number of columns 3713 . nz - number of nonzeros per row (same for all rows) 3714 - nnz - array containing the number of nonzeros in the various rows 3715 (possibly different for each row) or NULL 3716 3717 Output Parameter: 3718 . A - the matrix 3719 3720 It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`, 3721 MatXXXXSetPreallocation() paradigm instead of this routine directly. 3722 [MatXXXXSetPreallocation() is, for example, `MatSeqAIJSetPreallocation()`] 3723 3724 Notes: 3725 If nnz is given then nz is ignored 3726 3727 The AIJ format, also called 3728 compressed row storage, is fully compatible with standard Fortran 77 3729 storage. That is, the stored row and column indices can begin at 3730 either one (as in Fortran) or zero. See the users' manual for details. 3731 3732 Specify the preallocated storage with either nz or nnz (not both). 3733 Set nz = `PETSC_DEFAULT` and nnz = NULL for PETSc to control dynamic memory 3734 allocation. For large problems you MUST preallocate memory or you 3735 will get TERRIBLE performance, see the users' manual chapter on matrices. 3736 3737 By default, this format uses inodes (identical nodes) when possible, to 3738 improve numerical efficiency of matrix-vector products and solves. We 3739 search for consecutive rows with the same nonzero structure, thereby 3740 reusing matrix information to achieve increased efficiency. 3741 3742 Options Database Keys: 3743 + -mat_no_inode - Do not use inodes 3744 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3745 3746 Level: intermediate 3747 3748 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()` 3749 @*/ 3750 PetscErrorCode MatCreateSeqAIJ(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt nz, const PetscInt nnz[], Mat *A) { 3751 PetscFunctionBegin; 3752 PetscCall(MatCreate(comm, A)); 3753 PetscCall(MatSetSizes(*A, m, n, m, n)); 3754 PetscCall(MatSetType(*A, MATSEQAIJ)); 3755 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*A, nz, nnz)); 3756 PetscFunctionReturn(0); 3757 } 3758 3759 /*@C 3760 MatSeqAIJSetPreallocation - For good matrix assembly performance 3761 the user should preallocate the matrix storage by setting the parameter nz 3762 (or the array nnz). By setting these parameters accurately, performance 3763 during matrix assembly can be increased by more than a factor of 50. 3764 3765 Collective 3766 3767 Input Parameters: 3768 + B - The matrix 3769 . nz - number of nonzeros per row (same for all rows) 3770 - nnz - array containing the number of nonzeros in the various rows 3771 (possibly different for each row) or NULL 3772 3773 Notes: 3774 If nnz is given then nz is ignored 3775 3776 The `MATSEQAIJ` format also called 3777 compressed row storage, is fully compatible with standard Fortran 77 3778 storage. That is, the stored row and column indices can begin at 3779 either one (as in Fortran) or zero. See the users' manual for details. 3780 3781 Specify the preallocated storage with either nz or nnz (not both). 3782 Set nz = `PETSC_DEFAULT` and nnz = NULL for PETSc to control dynamic memory 3783 allocation. For large problems you MUST preallocate memory or you 3784 will get TERRIBLE performance, see the users' manual chapter on matrices. 3785 3786 You can call `MatGetInfo()` to get information on how effective the preallocation was; 3787 for example the fields mallocs,nz_allocated,nz_used,nz_unneeded; 3788 You can also run with the option -info and look for messages with the string 3789 malloc in them to see if additional memory allocation was needed. 3790 3791 Developer Notes: 3792 Use nz of `MAT_SKIP_ALLOCATION` to not allocate any space for the matrix 3793 entries or columns indices 3794 3795 By default, this format uses inodes (identical nodes) when possible, to 3796 improve numerical efficiency of matrix-vector products and solves. We 3797 search for consecutive rows with the same nonzero structure, thereby 3798 reusing matrix information to achieve increased efficiency. 3799 3800 Options Database Keys: 3801 + -mat_no_inode - Do not use inodes 3802 - -mat_inode_limit <limit> - Sets inode limit (max limit=5) 3803 3804 Level: intermediate 3805 3806 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()`, `MatGetInfo()`, 3807 `MatSeqAIJSetTotalPreallocation()` 3808 @*/ 3809 PetscErrorCode MatSeqAIJSetPreallocation(Mat B, PetscInt nz, const PetscInt nnz[]) { 3810 PetscFunctionBegin; 3811 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 3812 PetscValidType(B, 1); 3813 PetscTryMethod(B, "MatSeqAIJSetPreallocation_C", (Mat, PetscInt, const PetscInt[]), (B, nz, nnz)); 3814 PetscFunctionReturn(0); 3815 } 3816 3817 PetscErrorCode MatSeqAIJSetPreallocation_SeqAIJ(Mat B, PetscInt nz, const PetscInt *nnz) { 3818 Mat_SeqAIJ *b; 3819 PetscBool skipallocation = PETSC_FALSE, realalloc = PETSC_FALSE; 3820 PetscInt i; 3821 3822 PetscFunctionBegin; 3823 if (nz >= 0 || nnz) realalloc = PETSC_TRUE; 3824 if (nz == MAT_SKIP_ALLOCATION) { 3825 skipallocation = PETSC_TRUE; 3826 nz = 0; 3827 } 3828 PetscCall(PetscLayoutSetUp(B->rmap)); 3829 PetscCall(PetscLayoutSetUp(B->cmap)); 3830 3831 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5; 3832 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nz cannot be less than 0: value %" PetscInt_FMT, nz); 3833 if (PetscUnlikelyDebug(nnz)) { 3834 for (i = 0; i < B->rmap->n; i++) { 3835 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]); 3836 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); 3837 } 3838 } 3839 3840 B->preallocated = PETSC_TRUE; 3841 3842 b = (Mat_SeqAIJ *)B->data; 3843 3844 if (!skipallocation) { 3845 if (!b->imax) { 3846 PetscCall(PetscMalloc1(B->rmap->n, &b->imax)); 3847 PetscCall(PetscLogObjectMemory((PetscObject)B, B->rmap->n * sizeof(PetscInt))); 3848 } 3849 if (!b->ilen) { 3850 /* b->ilen will count nonzeros in each row so far. */ 3851 PetscCall(PetscCalloc1(B->rmap->n, &b->ilen)); 3852 PetscCall(PetscLogObjectMemory((PetscObject)B, B->rmap->n * sizeof(PetscInt))); 3853 } else { 3854 PetscCall(PetscMemzero(b->ilen, B->rmap->n * sizeof(PetscInt))); 3855 } 3856 if (!b->ipre) { 3857 PetscCall(PetscMalloc1(B->rmap->n, &b->ipre)); 3858 PetscCall(PetscLogObjectMemory((PetscObject)B, B->rmap->n * sizeof(PetscInt))); 3859 } 3860 if (!nnz) { 3861 if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 10; 3862 else if (nz < 0) nz = 1; 3863 nz = PetscMin(nz, B->cmap->n); 3864 for (i = 0; i < B->rmap->n; i++) b->imax[i] = nz; 3865 nz = nz * B->rmap->n; 3866 } else { 3867 PetscInt64 nz64 = 0; 3868 for (i = 0; i < B->rmap->n; i++) { 3869 b->imax[i] = nnz[i]; 3870 nz64 += nnz[i]; 3871 } 3872 PetscCall(PetscIntCast(nz64, &nz)); 3873 } 3874 3875 /* allocate the matrix space */ 3876 /* FIXME: should B's old memory be unlogged? */ 3877 PetscCall(MatSeqXAIJFreeAIJ(B, &b->a, &b->j, &b->i)); 3878 if (B->structure_only) { 3879 PetscCall(PetscMalloc1(nz, &b->j)); 3880 PetscCall(PetscMalloc1(B->rmap->n + 1, &b->i)); 3881 PetscCall(PetscLogObjectMemory((PetscObject)B, (B->rmap->n + 1) * sizeof(PetscInt) + nz * sizeof(PetscInt))); 3882 } else { 3883 PetscCall(PetscMalloc3(nz, &b->a, nz, &b->j, B->rmap->n + 1, &b->i)); 3884 PetscCall(PetscLogObjectMemory((PetscObject)B, (B->rmap->n + 1) * sizeof(PetscInt) + nz * (sizeof(PetscScalar) + sizeof(PetscInt)))); 3885 } 3886 b->i[0] = 0; 3887 for (i = 1; i < B->rmap->n + 1; i++) b->i[i] = b->i[i - 1] + b->imax[i - 1]; 3888 if (B->structure_only) { 3889 b->singlemalloc = PETSC_FALSE; 3890 b->free_a = PETSC_FALSE; 3891 } else { 3892 b->singlemalloc = PETSC_TRUE; 3893 b->free_a = PETSC_TRUE; 3894 } 3895 b->free_ij = PETSC_TRUE; 3896 } else { 3897 b->free_a = PETSC_FALSE; 3898 b->free_ij = PETSC_FALSE; 3899 } 3900 3901 if (b->ipre && nnz != b->ipre && b->imax) { 3902 /* reserve user-requested sparsity */ 3903 PetscCall(PetscArraycpy(b->ipre, b->imax, B->rmap->n)); 3904 } 3905 3906 b->nz = 0; 3907 b->maxnz = nz; 3908 B->info.nz_unneeded = (double)b->maxnz; 3909 if (realalloc) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 3910 B->was_assembled = PETSC_FALSE; 3911 B->assembled = PETSC_FALSE; 3912 /* We simply deem preallocation has changed nonzero state. Updating the state 3913 will give clients (like AIJKokkos) a chance to know something has happened. 3914 */ 3915 B->nonzerostate++; 3916 PetscFunctionReturn(0); 3917 } 3918 3919 PetscErrorCode MatResetPreallocation_SeqAIJ(Mat A) { 3920 Mat_SeqAIJ *a; 3921 PetscInt i; 3922 3923 PetscFunctionBegin; 3924 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 3925 3926 /* Check local size. If zero, then return */ 3927 if (!A->rmap->n) PetscFunctionReturn(0); 3928 3929 a = (Mat_SeqAIJ *)A->data; 3930 /* if no saved info, we error out */ 3931 PetscCheck(a->ipre, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "No saved preallocation info "); 3932 3933 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 "); 3934 3935 PetscCall(PetscArraycpy(a->imax, a->ipre, A->rmap->n)); 3936 PetscCall(PetscArrayzero(a->ilen, A->rmap->n)); 3937 a->i[0] = 0; 3938 for (i = 1; i < A->rmap->n + 1; i++) a->i[i] = a->i[i - 1] + a->imax[i - 1]; 3939 A->preallocated = PETSC_TRUE; 3940 a->nz = 0; 3941 a->maxnz = a->i[A->rmap->n]; 3942 A->info.nz_unneeded = (double)a->maxnz; 3943 A->was_assembled = PETSC_FALSE; 3944 A->assembled = PETSC_FALSE; 3945 PetscFunctionReturn(0); 3946 } 3947 3948 /*@ 3949 MatSeqAIJSetPreallocationCSR - Allocates memory for a sparse sequential matrix in `MATSEQAIJ` format. 3950 3951 Input Parameters: 3952 + B - the matrix 3953 . i - the indices into j for the start of each row (starts with zero) 3954 . j - the column indices for each row (starts with zero) these must be sorted for each row 3955 - v - optional values in the matrix 3956 3957 Level: developer 3958 3959 Notes: 3960 The i,j,v values are COPIED with this routine; to avoid the copy use `MatCreateSeqAIJWithArrays()` 3961 3962 This routine may be called multiple times with different nonzero patterns (or the same nonzero pattern). The nonzero 3963 structure will be the union of all the previous nonzero structures. 3964 3965 Developer Notes: 3966 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 3967 then just copies the v values directly with `PetscMemcpy()`. 3968 3969 This routine could also take a `PetscCopyMode` argument to allow sharing the values instead of always copying them. 3970 3971 .seealso: `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatSeqAIJSetPreallocation()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MatResetPreallocation()` 3972 @*/ 3973 PetscErrorCode MatSeqAIJSetPreallocationCSR(Mat B, const PetscInt i[], const PetscInt j[], const PetscScalar v[]) { 3974 PetscFunctionBegin; 3975 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 3976 PetscValidType(B, 1); 3977 PetscTryMethod(B, "MatSeqAIJSetPreallocationCSR_C", (Mat, const PetscInt[], const PetscInt[], const PetscScalar[]), (B, i, j, v)); 3978 PetscFunctionReturn(0); 3979 } 3980 3981 PetscErrorCode MatSeqAIJSetPreallocationCSR_SeqAIJ(Mat B, const PetscInt Ii[], const PetscInt J[], const PetscScalar v[]) { 3982 PetscInt i; 3983 PetscInt m, n; 3984 PetscInt nz; 3985 PetscInt *nnz; 3986 3987 PetscFunctionBegin; 3988 PetscCheck(Ii[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Ii[0] must be 0 it is %" PetscInt_FMT, Ii[0]); 3989 3990 PetscCall(PetscLayoutSetUp(B->rmap)); 3991 PetscCall(PetscLayoutSetUp(B->cmap)); 3992 3993 PetscCall(MatGetSize(B, &m, &n)); 3994 PetscCall(PetscMalloc1(m + 1, &nnz)); 3995 for (i = 0; i < m; i++) { 3996 nz = Ii[i + 1] - Ii[i]; 3997 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT, i, nz); 3998 nnz[i] = nz; 3999 } 4000 PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz)); 4001 PetscCall(PetscFree(nnz)); 4002 4003 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)); 4004 4005 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 4006 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 4007 4008 PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE)); 4009 PetscFunctionReturn(0); 4010 } 4011 4012 /*@ 4013 MatSeqAIJKron - Computes C, the Kronecker product of A and B. 4014 4015 Input Parameters: 4016 + A - left-hand side matrix 4017 . B - right-hand side matrix 4018 - reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX` 4019 4020 Output Parameter: 4021 . C - Kronecker product of A and B 4022 4023 Level: intermediate 4024 4025 Note: 4026 `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the product matrix has not changed from that last call to `MatSeqAIJKron()`. 4027 4028 .seealso: `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATKAIJ`, `MatReuse` 4029 @*/ 4030 PetscErrorCode MatSeqAIJKron(Mat A, Mat B, MatReuse reuse, Mat *C) { 4031 PetscFunctionBegin; 4032 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 4033 PetscValidType(A, 1); 4034 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 4035 PetscValidType(B, 2); 4036 PetscValidPointer(C, 4); 4037 if (reuse == MAT_REUSE_MATRIX) { 4038 PetscValidHeaderSpecific(*C, MAT_CLASSID, 4); 4039 PetscValidType(*C, 4); 4040 } 4041 PetscTryMethod(A, "MatSeqAIJKron_C", (Mat, Mat, MatReuse, Mat *), (A, B, reuse, C)); 4042 PetscFunctionReturn(0); 4043 } 4044 4045 PetscErrorCode MatSeqAIJKron_SeqAIJ(Mat A, Mat B, MatReuse reuse, Mat *C) { 4046 Mat newmat; 4047 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 4048 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 4049 PetscScalar *v; 4050 const PetscScalar *aa, *ba; 4051 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; 4052 PetscBool flg; 4053 4054 PetscFunctionBegin; 4055 PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4056 PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4057 PetscCheck(!B->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 4058 PetscCheck(B->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 4059 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &flg)); 4060 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatType %s", ((PetscObject)B)->type_name); 4061 PetscCheck(reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatReuse %d", (int)reuse); 4062 if (reuse == MAT_INITIAL_MATRIX) { 4063 PetscCall(PetscMalloc2(am * bm + 1, &i, a->i[am] * b->i[bm], &j)); 4064 PetscCall(MatCreate(PETSC_COMM_SELF, &newmat)); 4065 PetscCall(MatSetSizes(newmat, am * bm, an * bn, am * bm, an * bn)); 4066 PetscCall(MatSetType(newmat, MATAIJ)); 4067 i[0] = 0; 4068 for (m = 0; m < am; ++m) { 4069 for (p = 0; p < bm; ++p) { 4070 i[m * bm + p + 1] = i[m * bm + p] + (a->i[m + 1] - a->i[m]) * (b->i[p + 1] - b->i[p]); 4071 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4072 for (q = b->i[p]; q < b->i[p + 1]; ++q) j[nnz++] = a->j[n] * bn + b->j[q]; 4073 } 4074 } 4075 } 4076 PetscCall(MatSeqAIJSetPreallocationCSR(newmat, i, j, NULL)); 4077 *C = newmat; 4078 PetscCall(PetscFree2(i, j)); 4079 nnz = 0; 4080 } 4081 PetscCall(MatSeqAIJGetArray(*C, &v)); 4082 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4083 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 4084 for (m = 0; m < am; ++m) { 4085 for (p = 0; p < bm; ++p) { 4086 for (n = a->i[m]; n < a->i[m + 1]; ++n) { 4087 for (q = b->i[p]; q < b->i[p + 1]; ++q) v[nnz++] = aa[n] * ba[q]; 4088 } 4089 } 4090 } 4091 PetscCall(MatSeqAIJRestoreArray(*C, &v)); 4092 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 4093 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 4094 PetscFunctionReturn(0); 4095 } 4096 4097 #include <../src/mat/impls/dense/seq/dense.h> 4098 #include <petsc/private/kernels/petscaxpy.h> 4099 4100 /* 4101 Computes (B'*A')' since computing B*A directly is untenable 4102 4103 n p p 4104 [ ] [ ] [ ] 4105 m [ A ] * n [ B ] = m [ C ] 4106 [ ] [ ] [ ] 4107 4108 */ 4109 PetscErrorCode MatMatMultNumeric_SeqDense_SeqAIJ(Mat A, Mat B, Mat C) { 4110 Mat_SeqDense *sub_a = (Mat_SeqDense *)A->data; 4111 Mat_SeqAIJ *sub_b = (Mat_SeqAIJ *)B->data; 4112 Mat_SeqDense *sub_c = (Mat_SeqDense *)C->data; 4113 PetscInt i, j, n, m, q, p; 4114 const PetscInt *ii, *idx; 4115 const PetscScalar *b, *a, *a_q; 4116 PetscScalar *c, *c_q; 4117 PetscInt clda = sub_c->lda; 4118 PetscInt alda = sub_a->lda; 4119 4120 PetscFunctionBegin; 4121 m = A->rmap->n; 4122 n = A->cmap->n; 4123 p = B->cmap->n; 4124 a = sub_a->v; 4125 b = sub_b->a; 4126 c = sub_c->v; 4127 if (clda == m) { 4128 PetscCall(PetscArrayzero(c, m * p)); 4129 } else { 4130 for (j = 0; j < p; j++) 4131 for (i = 0; i < m; i++) c[j * clda + i] = 0.0; 4132 } 4133 ii = sub_b->i; 4134 idx = sub_b->j; 4135 for (i = 0; i < n; i++) { 4136 q = ii[i + 1] - ii[i]; 4137 while (q-- > 0) { 4138 c_q = c + clda * (*idx); 4139 a_q = a + alda * i; 4140 PetscKernelAXPY(c_q, *b, a_q, m); 4141 idx++; 4142 b++; 4143 } 4144 } 4145 PetscFunctionReturn(0); 4146 } 4147 4148 PetscErrorCode MatMatMultSymbolic_SeqDense_SeqAIJ(Mat A, Mat B, PetscReal fill, Mat C) { 4149 PetscInt m = A->rmap->n, n = B->cmap->n; 4150 PetscBool cisdense; 4151 4152 PetscFunctionBegin; 4153 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); 4154 PetscCall(MatSetSizes(C, m, n, m, n)); 4155 PetscCall(MatSetBlockSizesFromMats(C, A, B)); 4156 PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATSEQDENSECUDA, "")); 4157 if (!cisdense) PetscCall(MatSetType(C, MATDENSE)); 4158 PetscCall(MatSetUp(C)); 4159 4160 C->ops->matmultnumeric = MatMatMultNumeric_SeqDense_SeqAIJ; 4161 PetscFunctionReturn(0); 4162 } 4163 4164 /* ----------------------------------------------------------------*/ 4165 /*MC 4166 MATSEQAIJ - MATSEQAIJ = "seqaij" - A matrix type to be used for sequential sparse matrices, 4167 based on compressed sparse row format. 4168 4169 Options Database Keys: 4170 . -mat_type seqaij - sets the matrix type to "seqaij" during a call to MatSetFromOptions() 4171 4172 Level: beginner 4173 4174 Notes: 4175 `MatSetValues()` may be called for this matrix type with a NULL argument for the numerical values, 4176 in this case the values associated with the rows and columns one passes in are set to zero 4177 in the matrix 4178 4179 `MatSetOptions`(,`MAT_STRUCTURE_ONLY`,`PETSC_TRUE`) may be called for this matrix type. In this no 4180 space is allocated for the nonzero entries and any entries passed with `MatSetValues()` are ignored 4181 4182 Developer Note: 4183 It would be nice if all matrix formats supported passing NULL in for the numerical values 4184 4185 .seealso: `MatCreateSeqAIJ()`, `MatSetFromOptions()`, `MatSetType()`, `MatCreate()`, `MatType`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4186 M*/ 4187 4188 /*MC 4189 MATAIJ - MATAIJ = "aij" - A matrix type to be used for sparse matrices. 4190 4191 This matrix type is identical to `MATSEQAIJ` when constructed with a single process communicator, 4192 and `MATMPIAIJ` otherwise. As a result, for single process communicators, 4193 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4194 for communicators controlling multiple processes. It is recommended that you call both of 4195 the above preallocation routines for simplicity. 4196 4197 Options Database Keys: 4198 . -mat_type aij - sets the matrix type to "aij" during a call to `MatSetFromOptions()` 4199 4200 Note: 4201 Subclasses include `MATAIJCUSPARSE`, `MATAIJPERM`, `MATAIJSELL`, `MATAIJMKL`, `MATAIJCRL`, and also automatically switches over to use inodes when 4202 enough exist. 4203 4204 Level: beginner 4205 4206 .seealso: `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATMPIAIJ`, `MATSELL`, `MATSEQSELL`, `MATMPISELL` 4207 M*/ 4208 4209 /*MC 4210 MATAIJCRL - MATAIJCRL = "aijcrl" - A matrix type to be used for sparse matrices. 4211 4212 This matrix type is identical to `MATSEQAIJCRL` when constructed with a single process communicator, 4213 and `MATMPIAIJCRL` otherwise. As a result, for single process communicators, 4214 `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported 4215 for communicators controlling multiple processes. It is recommended that you call both of 4216 the above preallocation routines for simplicity. 4217 4218 Options Database Keys: 4219 . -mat_type aijcrl - sets the matrix type to "aijcrl" during a call to `MatSetFromOptions()` 4220 4221 Level: beginner 4222 4223 .seealso: `MatCreateMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL` 4224 M*/ 4225 4226 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCRL(Mat, MatType, MatReuse, Mat *); 4227 #if defined(PETSC_HAVE_ELEMENTAL) 4228 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat, MatType, MatReuse, Mat *); 4229 #endif 4230 #if defined(PETSC_HAVE_SCALAPACK) 4231 PETSC_INTERN PetscErrorCode MatConvert_AIJ_ScaLAPACK(Mat, MatType, MatReuse, Mat *); 4232 #endif 4233 #if defined(PETSC_HAVE_HYPRE) 4234 PETSC_INTERN PetscErrorCode MatConvert_AIJ_HYPRE(Mat A, MatType, MatReuse, Mat *); 4235 #endif 4236 4237 PETSC_EXTERN PetscErrorCode MatConvert_SeqAIJ_SeqSELL(Mat, MatType, MatReuse, Mat *); 4238 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat, MatType, MatReuse, Mat *); 4239 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat); 4240 4241 /*@C 4242 MatSeqAIJGetArray - gives read/write access to the array where the data for a `MATSEQAIJ` matrix is stored 4243 4244 Not Collective 4245 4246 Input Parameter: 4247 . mat - a `MATSEQAIJ` matrix 4248 4249 Output Parameter: 4250 . array - pointer to the data 4251 4252 Level: intermediate 4253 4254 .seealso: `MatSeqAIJRestoreArray()`, `MatSeqAIJGetArrayF90()` 4255 @*/ 4256 PetscErrorCode MatSeqAIJGetArray(Mat A, PetscScalar **array) { 4257 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4258 4259 PetscFunctionBegin; 4260 if (aij->ops->getarray) { 4261 PetscCall((*aij->ops->getarray)(A, array)); 4262 } else { 4263 *array = aij->a; 4264 } 4265 PetscFunctionReturn(0); 4266 } 4267 4268 /*@C 4269 MatSeqAIJRestoreArray - returns access to the array where the data for a `MATSEQAIJ` matrix is stored obtained by `MatSeqAIJGetArray()` 4270 4271 Not Collective 4272 4273 Input Parameters: 4274 + mat - a `MATSEQAIJ` matrix 4275 - array - pointer to the data 4276 4277 Level: intermediate 4278 4279 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayF90()` 4280 @*/ 4281 PetscErrorCode MatSeqAIJRestoreArray(Mat A, PetscScalar **array) { 4282 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4283 4284 PetscFunctionBegin; 4285 if (aij->ops->restorearray) { 4286 PetscCall((*aij->ops->restorearray)(A, array)); 4287 } else { 4288 *array = NULL; 4289 } 4290 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4291 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4292 PetscFunctionReturn(0); 4293 } 4294 4295 /*@C 4296 MatSeqAIJGetArrayRead - gives read-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4297 4298 Not Collective 4299 4300 Input Parameter: 4301 . mat - a `MATSEQAIJ` matrix 4302 4303 Output Parameter: 4304 . array - pointer to the data 4305 4306 Level: intermediate 4307 4308 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4309 @*/ 4310 PetscErrorCode MatSeqAIJGetArrayRead(Mat A, const PetscScalar **array) { 4311 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4312 4313 PetscFunctionBegin; 4314 if (aij->ops->getarrayread) { 4315 PetscCall((*aij->ops->getarrayread)(A, array)); 4316 } else { 4317 *array = aij->a; 4318 } 4319 PetscFunctionReturn(0); 4320 } 4321 4322 /*@C 4323 MatSeqAIJRestoreArrayRead - restore the read-only access array obtained from `MatSeqAIJGetArrayRead()` 4324 4325 Not Collective 4326 4327 Input Parameter: 4328 . mat - a `MATSEQAIJ` matrix 4329 4330 Output Parameter: 4331 . array - pointer to the data 4332 4333 Level: intermediate 4334 4335 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4336 @*/ 4337 PetscErrorCode MatSeqAIJRestoreArrayRead(Mat A, const PetscScalar **array) { 4338 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4339 4340 PetscFunctionBegin; 4341 if (aij->ops->restorearrayread) { 4342 PetscCall((*aij->ops->restorearrayread)(A, array)); 4343 } else { 4344 *array = NULL; 4345 } 4346 PetscFunctionReturn(0); 4347 } 4348 4349 /*@C 4350 MatSeqAIJGetArrayWrite - gives write-only access to the array where the data for a `MATSEQAIJ` matrix is stored 4351 4352 Not Collective 4353 4354 Input Parameter: 4355 . mat - a `MATSEQAIJ` matrix 4356 4357 Output Parameter: 4358 . array - pointer to the data 4359 4360 Level: intermediate 4361 4362 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()` 4363 @*/ 4364 PetscErrorCode MatSeqAIJGetArrayWrite(Mat A, PetscScalar **array) { 4365 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4366 4367 PetscFunctionBegin; 4368 if (aij->ops->getarraywrite) { 4369 PetscCall((*aij->ops->getarraywrite)(A, array)); 4370 } else { 4371 *array = aij->a; 4372 } 4373 PetscCall(MatSeqAIJInvalidateDiagonal(A)); 4374 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 4375 PetscFunctionReturn(0); 4376 } 4377 4378 /*@C 4379 MatSeqAIJRestoreArrayWrite - restore the read-only access array obtained from MatSeqAIJGetArrayRead 4380 4381 Not Collective 4382 4383 Input Parameter: 4384 . mat - a MATSEQAIJ matrix 4385 4386 Output Parameter: 4387 . array - pointer to the data 4388 4389 Level: intermediate 4390 4391 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4392 @*/ 4393 PetscErrorCode MatSeqAIJRestoreArrayWrite(Mat A, PetscScalar **array) { 4394 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4395 4396 PetscFunctionBegin; 4397 if (aij->ops->restorearraywrite) { 4398 PetscCall((*aij->ops->restorearraywrite)(A, array)); 4399 } else { 4400 *array = NULL; 4401 } 4402 PetscFunctionReturn(0); 4403 } 4404 4405 /*@C 4406 MatSeqAIJGetCSRAndMemType - Get the CSR arrays and the memory type of the `MATSEQAIJ` matrix 4407 4408 Not Collective 4409 4410 Input Parameter: 4411 . mat - a matrix of type `MATSEQAIJ` or its subclasses 4412 4413 Output Parameters: 4414 + i - row map array of the matrix 4415 . j - column index array of the matrix 4416 . a - data array of the matrix 4417 - memtype - memory type of the arrays 4418 4419 Notes: 4420 Any of the output parameters can be NULL, in which case the corresponding value is not returned. 4421 If mat is a device matrix, the arrays are on the device. Otherwise, they are on the host. 4422 4423 One can call this routine on a preallocated but not assembled matrix to just get the memory of the CSR underneath the matrix. 4424 If the matrix is assembled, the data array 'a' is guaranteed to have the latest values of the matrix. 4425 4426 Level: Developer 4427 4428 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()` 4429 @*/ 4430 PetscErrorCode MatSeqAIJGetCSRAndMemType(Mat mat, const PetscInt **i, const PetscInt **j, PetscScalar **a, PetscMemType *mtype) { 4431 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data; 4432 4433 PetscFunctionBegin; 4434 PetscCheck(mat->preallocated, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "matrix is not preallocated"); 4435 if (aij->ops->getcsrandmemtype) { 4436 PetscCall((*aij->ops->getcsrandmemtype)(mat, i, j, a, mtype)); 4437 } else { 4438 if (i) *i = aij->i; 4439 if (j) *j = aij->j; 4440 if (a) *a = aij->a; 4441 if (mtype) *mtype = PETSC_MEMTYPE_HOST; 4442 } 4443 PetscFunctionReturn(0); 4444 } 4445 4446 /*@C 4447 MatSeqAIJGetMaxRowNonzeros - returns the maximum number of nonzeros in any row 4448 4449 Not Collective 4450 4451 Input Parameter: 4452 . mat - a `MATSEQAIJ` matrix 4453 4454 Output Parameter: 4455 . nz - the maximum number of nonzeros in any row 4456 4457 Level: intermediate 4458 4459 .seealso: `MatSeqAIJRestoreArray()`, `MatSeqAIJGetArrayF90()` 4460 @*/ 4461 PetscErrorCode MatSeqAIJGetMaxRowNonzeros(Mat A, PetscInt *nz) { 4462 Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data; 4463 4464 PetscFunctionBegin; 4465 *nz = aij->rmax; 4466 PetscFunctionReturn(0); 4467 } 4468 4469 PetscErrorCode MatSetPreallocationCOO_SeqAIJ(Mat mat, PetscCount coo_n, PetscInt coo_i[], PetscInt coo_j[]) { 4470 MPI_Comm comm; 4471 PetscInt *i, *j; 4472 PetscInt M, N, row; 4473 PetscCount k, p, q, nneg, nnz, start, end; /* Index the coo array, so use PetscCount as their type */ 4474 PetscInt *Ai; /* Change to PetscCount once we use it for row pointers */ 4475 PetscInt *Aj; 4476 PetscScalar *Aa; 4477 Mat_SeqAIJ *seqaij = (Mat_SeqAIJ *)(mat->data); 4478 MatType rtype; 4479 PetscCount *perm, *jmap; 4480 4481 PetscFunctionBegin; 4482 PetscCall(MatResetPreallocationCOO_SeqAIJ(mat)); 4483 PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 4484 PetscCall(MatGetSize(mat, &M, &N)); 4485 i = coo_i; 4486 j = coo_j; 4487 PetscCall(PetscMalloc1(coo_n, &perm)); 4488 for (k = 0; k < coo_n; k++) { /* Ignore entries with negative row or col indices */ 4489 if (j[k] < 0) i[k] = -1; 4490 perm[k] = k; 4491 } 4492 4493 /* Sort by row */ 4494 PetscCall(PetscSortIntWithIntCountArrayPair(coo_n, i, j, perm)); 4495 for (k = 0; k < coo_n; k++) { 4496 if (i[k] >= 0) break; 4497 } /* Advance k to the first row with a non-negative index */ 4498 nneg = k; 4499 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 */ 4500 nnz = 0; /* Total number of unique nonzeros to be counted */ 4501 jmap++; /* Inc jmap by 1 for convinience */ 4502 4503 PetscCall(PetscCalloc1(M + 1, &Ai)); /* CSR of A */ 4504 PetscCall(PetscMalloc1(coo_n - nneg, &Aj)); /* We have at most coo_n-nneg unique nonzeros */ 4505 4506 /* In each row, sort by column, then unique column indices to get row length */ 4507 Ai++; /* Inc by 1 for convinience */ 4508 q = 0; /* q-th unique nonzero, with q starting from 0 */ 4509 while (k < coo_n) { 4510 row = i[k]; 4511 start = k; /* [start,end) indices for this row */ 4512 while (k < coo_n && i[k] == row) k++; 4513 end = k; 4514 PetscCall(PetscSortIntWithCountArray(end - start, j + start, perm + start)); 4515 /* Find number of unique col entries in this row */ 4516 Aj[q] = j[start]; /* Log the first nonzero in this row */ 4517 jmap[q] = 1; /* Number of repeats of this nozero entry */ 4518 Ai[row] = 1; 4519 nnz++; 4520 4521 for (p = start + 1; p < end; p++) { /* Scan remaining nonzero in this row */ 4522 if (j[p] != j[p - 1]) { /* Meet a new nonzero */ 4523 q++; 4524 jmap[q] = 1; 4525 Aj[q] = j[p]; 4526 Ai[row]++; 4527 nnz++; 4528 } else { 4529 jmap[q]++; 4530 } 4531 } 4532 q++; /* Move to next row and thus next unique nonzero */ 4533 } 4534 4535 Ai--; /* Back to the beginning of Ai[] */ 4536 for (k = 0; k < M; k++) Ai[k + 1] += Ai[k]; 4537 jmap--; /* Back to the beginning of jmap[] */ 4538 jmap[0] = 0; 4539 for (k = 0; k < nnz; k++) jmap[k + 1] += jmap[k]; 4540 if (nnz < coo_n - nneg) { /* Realloc with actual number of unique nonzeros */ 4541 PetscCount *jmap_new; 4542 PetscInt *Aj_new; 4543 4544 PetscCall(PetscMalloc1(nnz + 1, &jmap_new)); 4545 PetscCall(PetscArraycpy(jmap_new, jmap, nnz + 1)); 4546 PetscCall(PetscFree(jmap)); 4547 jmap = jmap_new; 4548 4549 PetscCall(PetscMalloc1(nnz, &Aj_new)); 4550 PetscCall(PetscArraycpy(Aj_new, Aj, nnz)); 4551 PetscCall(PetscFree(Aj)); 4552 Aj = Aj_new; 4553 } 4554 4555 if (nneg) { /* Discard heading entries with negative indices in perm[], as we'll access it from index 0 in MatSetValuesCOO */ 4556 PetscCount *perm_new; 4557 4558 PetscCall(PetscMalloc1(coo_n - nneg, &perm_new)); 4559 PetscCall(PetscArraycpy(perm_new, perm + nneg, coo_n - nneg)); 4560 PetscCall(PetscFree(perm)); 4561 perm = perm_new; 4562 } 4563 4564 PetscCall(MatGetRootType_Private(mat, &rtype)); 4565 PetscCall(PetscCalloc1(nnz, &Aa)); /* Zero the matrix */ 4566 PetscCall(MatSetSeqAIJWithArrays_private(PETSC_COMM_SELF, M, N, Ai, Aj, Aa, rtype, mat)); 4567 4568 seqaij->singlemalloc = PETSC_FALSE; /* Ai, Aj and Aa are not allocated in one big malloc */ 4569 seqaij->free_a = seqaij->free_ij = PETSC_TRUE; /* Let newmat own Ai, Aj and Aa */ 4570 /* Record COO fields */ 4571 seqaij->coo_n = coo_n; 4572 seqaij->Atot = coo_n - nneg; /* Annz is seqaij->nz, so no need to record that again */ 4573 seqaij->jmap = jmap; /* of length nnz+1 */ 4574 seqaij->perm = perm; 4575 PetscFunctionReturn(0); 4576 } 4577 4578 static PetscErrorCode MatSetValuesCOO_SeqAIJ(Mat A, const PetscScalar v[], InsertMode imode) { 4579 Mat_SeqAIJ *aseq = (Mat_SeqAIJ *)A->data; 4580 PetscCount i, j, Annz = aseq->nz; 4581 PetscCount *perm = aseq->perm, *jmap = aseq->jmap; 4582 PetscScalar *Aa; 4583 4584 PetscFunctionBegin; 4585 PetscCall(MatSeqAIJGetArray(A, &Aa)); 4586 for (i = 0; i < Annz; i++) { 4587 PetscScalar sum = 0.0; 4588 for (j = jmap[i]; j < jmap[i + 1]; j++) sum += v[perm[j]]; 4589 Aa[i] = (imode == INSERT_VALUES ? 0.0 : Aa[i]) + sum; 4590 } 4591 PetscCall(MatSeqAIJRestoreArray(A, &Aa)); 4592 PetscFunctionReturn(0); 4593 } 4594 4595 #if defined(PETSC_HAVE_CUDA) 4596 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCUSPARSE(Mat, MatType, MatReuse, Mat *); 4597 #endif 4598 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4599 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJKokkos(Mat, MatType, MatReuse, Mat *); 4600 #endif 4601 4602 PETSC_EXTERN PetscErrorCode MatCreate_SeqAIJ(Mat B) { 4603 Mat_SeqAIJ *b; 4604 PetscMPIInt size; 4605 4606 PetscFunctionBegin; 4607 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size)); 4608 PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Comm must be of size 1"); 4609 4610 PetscCall(PetscNewLog(B, &b)); 4611 4612 B->data = (void *)b; 4613 4614 PetscCall(PetscMemcpy(B->ops, &MatOps_Values, sizeof(struct _MatOps))); 4615 if (B->sortedfull) B->ops->setvalues = MatSetValues_SeqAIJ_SortedFull; 4616 4617 b->row = NULL; 4618 b->col = NULL; 4619 b->icol = NULL; 4620 b->reallocs = 0; 4621 b->ignorezeroentries = PETSC_FALSE; 4622 b->roworiented = PETSC_TRUE; 4623 b->nonew = 0; 4624 b->diag = NULL; 4625 b->solve_work = NULL; 4626 B->spptr = NULL; 4627 b->saved_values = NULL; 4628 b->idiag = NULL; 4629 b->mdiag = NULL; 4630 b->ssor_work = NULL; 4631 b->omega = 1.0; 4632 b->fshift = 0.0; 4633 b->idiagvalid = PETSC_FALSE; 4634 b->ibdiagvalid = PETSC_FALSE; 4635 b->keepnonzeropattern = PETSC_FALSE; 4636 4637 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4638 #if defined(PETSC_HAVE_MATLAB_ENGINE) 4639 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEnginePut_C", MatlabEnginePut_SeqAIJ)); 4640 PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEngineGet_C", MatlabEngineGet_SeqAIJ)); 4641 #endif 4642 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetColumnIndices_C", MatSeqAIJSetColumnIndices_SeqAIJ)); 4643 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_SeqAIJ)); 4644 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_SeqAIJ)); 4645 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsbaij_C", MatConvert_SeqAIJ_SeqSBAIJ)); 4646 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqbaij_C", MatConvert_SeqAIJ_SeqBAIJ)); 4647 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijperm_C", MatConvert_SeqAIJ_SeqAIJPERM)); 4648 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijsell_C", MatConvert_SeqAIJ_SeqAIJSELL)); 4649 #if defined(PETSC_HAVE_MKL_SPARSE) 4650 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijmkl_C", MatConvert_SeqAIJ_SeqAIJMKL)); 4651 #endif 4652 #if defined(PETSC_HAVE_CUDA) 4653 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcusparse_C", MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 4654 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4655 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", MatProductSetFromOptions_SeqAIJ)); 4656 #endif 4657 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 4658 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijkokkos_C", MatConvert_SeqAIJ_SeqAIJKokkos)); 4659 #endif 4660 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcrl_C", MatConvert_SeqAIJ_SeqAIJCRL)); 4661 #if defined(PETSC_HAVE_ELEMENTAL) 4662 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_elemental_C", MatConvert_SeqAIJ_Elemental)); 4663 #endif 4664 #if defined(PETSC_HAVE_SCALAPACK) 4665 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_scalapack_C", MatConvert_AIJ_ScaLAPACK)); 4666 #endif 4667 #if defined(PETSC_HAVE_HYPRE) 4668 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_hypre_C", MatConvert_AIJ_HYPRE)); 4669 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", MatProductSetFromOptions_Transpose_AIJ_AIJ)); 4670 #endif 4671 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqdense_C", MatConvert_SeqAIJ_SeqDense)); 4672 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsell_C", MatConvert_SeqAIJ_SeqSELL)); 4673 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_is_C", MatConvert_XAIJ_IS)); 4674 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_SeqAIJ)); 4675 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsHermitianTranspose_C", MatIsTranspose_SeqAIJ)); 4676 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocation_C", MatSeqAIJSetPreallocation_SeqAIJ)); 4677 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetPreallocation_C", MatResetPreallocation_SeqAIJ)); 4678 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocationCSR_C", MatSeqAIJSetPreallocationCSR_SeqAIJ)); 4679 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatReorderForNonzeroDiagonal_C", MatReorderForNonzeroDiagonal_SeqAIJ)); 4680 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_is_seqaij_C", MatProductSetFromOptions_IS_XAIJ)); 4681 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqdense_seqaij_C", MatProductSetFromOptions_SeqDense_SeqAIJ)); 4682 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaij_C", MatProductSetFromOptions_SeqAIJ)); 4683 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJKron_C", MatSeqAIJKron_SeqAIJ)); 4684 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_SeqAIJ)); 4685 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetValuesCOO_C", MatSetValuesCOO_SeqAIJ)); 4686 PetscCall(MatCreate_SeqAIJ_Inode(B)); 4687 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ)); 4688 PetscCall(MatSeqAIJSetTypeFromOptions(B)); /* this allows changing the matrix subtype to say MATSEQAIJPERM */ 4689 PetscFunctionReturn(0); 4690 } 4691 4692 /* 4693 Given a matrix generated with MatGetFactor() duplicates all the information in A into C 4694 */ 4695 PetscErrorCode MatDuplicateNoCreate_SeqAIJ(Mat C, Mat A, MatDuplicateOption cpvalues, PetscBool mallocmatspace) { 4696 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data, *a = (Mat_SeqAIJ *)A->data; 4697 PetscInt m = A->rmap->n, i; 4698 4699 PetscFunctionBegin; 4700 PetscCheck(A->assembled || cpvalues == MAT_DO_NOT_COPY_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot duplicate unassembled matrix"); 4701 4702 C->factortype = A->factortype; 4703 c->row = NULL; 4704 c->col = NULL; 4705 c->icol = NULL; 4706 c->reallocs = 0; 4707 4708 C->assembled = A->assembled; 4709 C->preallocated = A->preallocated; 4710 4711 if (A->preallocated) { 4712 PetscCall(PetscLayoutReference(A->rmap, &C->rmap)); 4713 PetscCall(PetscLayoutReference(A->cmap, &C->cmap)); 4714 4715 PetscCall(PetscMalloc1(m, &c->imax)); 4716 PetscCall(PetscMemcpy(c->imax, a->imax, m * sizeof(PetscInt))); 4717 PetscCall(PetscMalloc1(m, &c->ilen)); 4718 PetscCall(PetscMemcpy(c->ilen, a->ilen, m * sizeof(PetscInt))); 4719 PetscCall(PetscLogObjectMemory((PetscObject)C, 2 * m * sizeof(PetscInt))); 4720 4721 /* allocate the matrix space */ 4722 if (mallocmatspace) { 4723 PetscCall(PetscMalloc3(a->i[m], &c->a, a->i[m], &c->j, m + 1, &c->i)); 4724 PetscCall(PetscLogObjectMemory((PetscObject)C, a->i[m] * (sizeof(PetscScalar) + sizeof(PetscInt)) + (m + 1) * sizeof(PetscInt))); 4725 4726 c->singlemalloc = PETSC_TRUE; 4727 4728 PetscCall(PetscArraycpy(c->i, a->i, m + 1)); 4729 if (m > 0) { 4730 PetscCall(PetscArraycpy(c->j, a->j, a->i[m])); 4731 if (cpvalues == MAT_COPY_VALUES) { 4732 const PetscScalar *aa; 4733 4734 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4735 PetscCall(PetscArraycpy(c->a, aa, a->i[m])); 4736 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4737 } else { 4738 PetscCall(PetscArrayzero(c->a, a->i[m])); 4739 } 4740 } 4741 } 4742 4743 c->ignorezeroentries = a->ignorezeroentries; 4744 c->roworiented = a->roworiented; 4745 c->nonew = a->nonew; 4746 if (a->diag) { 4747 PetscCall(PetscMalloc1(m + 1, &c->diag)); 4748 PetscCall(PetscMemcpy(c->diag, a->diag, m * sizeof(PetscInt))); 4749 PetscCall(PetscLogObjectMemory((PetscObject)C, (m + 1) * sizeof(PetscInt))); 4750 } else c->diag = NULL; 4751 4752 c->solve_work = NULL; 4753 c->saved_values = NULL; 4754 c->idiag = NULL; 4755 c->ssor_work = NULL; 4756 c->keepnonzeropattern = a->keepnonzeropattern; 4757 c->free_a = PETSC_TRUE; 4758 c->free_ij = PETSC_TRUE; 4759 4760 c->rmax = a->rmax; 4761 c->nz = a->nz; 4762 c->maxnz = a->nz; /* Since we allocate exactly the right amount */ 4763 4764 c->compressedrow.use = a->compressedrow.use; 4765 c->compressedrow.nrows = a->compressedrow.nrows; 4766 if (a->compressedrow.use) { 4767 i = a->compressedrow.nrows; 4768 PetscCall(PetscMalloc2(i + 1, &c->compressedrow.i, i, &c->compressedrow.rindex)); 4769 PetscCall(PetscArraycpy(c->compressedrow.i, a->compressedrow.i, i + 1)); 4770 PetscCall(PetscArraycpy(c->compressedrow.rindex, a->compressedrow.rindex, i)); 4771 } else { 4772 c->compressedrow.use = PETSC_FALSE; 4773 c->compressedrow.i = NULL; 4774 c->compressedrow.rindex = NULL; 4775 } 4776 c->nonzerorowcnt = a->nonzerorowcnt; 4777 C->nonzerostate = A->nonzerostate; 4778 4779 PetscCall(MatDuplicate_SeqAIJ_Inode(A, cpvalues, &C)); 4780 } 4781 PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist, &((PetscObject)C)->qlist)); 4782 PetscFunctionReturn(0); 4783 } 4784 4785 PetscErrorCode MatDuplicate_SeqAIJ(Mat A, MatDuplicateOption cpvalues, Mat *B) { 4786 PetscFunctionBegin; 4787 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 4788 PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->n, A->cmap->n)); 4789 if (!(A->rmap->n % A->rmap->bs) && !(A->cmap->n % A->cmap->bs)) PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 4790 PetscCall(MatSetType(*B, ((PetscObject)A)->type_name)); 4791 PetscCall(MatDuplicateNoCreate_SeqAIJ(*B, A, cpvalues, PETSC_TRUE)); 4792 PetscFunctionReturn(0); 4793 } 4794 4795 PetscErrorCode MatLoad_SeqAIJ(Mat newMat, PetscViewer viewer) { 4796 PetscBool isbinary, ishdf5; 4797 4798 PetscFunctionBegin; 4799 PetscValidHeaderSpecific(newMat, MAT_CLASSID, 1); 4800 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 4801 /* force binary viewer to load .info file if it has not yet done so */ 4802 PetscCall(PetscViewerSetUp(viewer)); 4803 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 4804 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 4805 if (isbinary) { 4806 PetscCall(MatLoad_SeqAIJ_Binary(newMat, viewer)); 4807 } else if (ishdf5) { 4808 #if defined(PETSC_HAVE_HDF5) 4809 PetscCall(MatLoad_AIJ_HDF5(newMat, viewer)); 4810 #else 4811 SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 4812 #endif 4813 } else { 4814 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); 4815 } 4816 PetscFunctionReturn(0); 4817 } 4818 4819 PetscErrorCode MatLoad_SeqAIJ_Binary(Mat mat, PetscViewer viewer) { 4820 Mat_SeqAIJ *a = (Mat_SeqAIJ *)mat->data; 4821 PetscInt header[4], *rowlens, M, N, nz, sum, rows, cols, i; 4822 4823 PetscFunctionBegin; 4824 PetscCall(PetscViewerSetUp(viewer)); 4825 4826 /* read in matrix header */ 4827 PetscCall(PetscViewerBinaryRead(viewer, header, 4, NULL, PETSC_INT)); 4828 PetscCheck(header[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix object in file"); 4829 M = header[1]; 4830 N = header[2]; 4831 nz = header[3]; 4832 PetscCheck(M >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix row size (%" PetscInt_FMT ") in file is negative", M); 4833 PetscCheck(N >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix column size (%" PetscInt_FMT ") in file is negative", N); 4834 PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix stored in special format on disk, cannot load as SeqAIJ"); 4835 4836 /* set block sizes from the viewer's .info file */ 4837 PetscCall(MatLoad_Binary_BlockSizes(mat, viewer)); 4838 /* set local and global sizes if not set already */ 4839 if (mat->rmap->n < 0) mat->rmap->n = M; 4840 if (mat->cmap->n < 0) mat->cmap->n = N; 4841 if (mat->rmap->N < 0) mat->rmap->N = M; 4842 if (mat->cmap->N < 0) mat->cmap->N = N; 4843 PetscCall(PetscLayoutSetUp(mat->rmap)); 4844 PetscCall(PetscLayoutSetUp(mat->cmap)); 4845 4846 /* check if the matrix sizes are correct */ 4847 PetscCall(MatGetSize(mat, &rows, &cols)); 4848 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); 4849 4850 /* read in row lengths */ 4851 PetscCall(PetscMalloc1(M, &rowlens)); 4852 PetscCall(PetscViewerBinaryRead(viewer, rowlens, M, NULL, PETSC_INT)); 4853 /* check if sum(rowlens) is same as nz */ 4854 sum = 0; 4855 for (i = 0; i < M; i++) sum += rowlens[i]; 4856 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); 4857 /* preallocate and check sizes */ 4858 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(mat, 0, rowlens)); 4859 PetscCall(MatGetSize(mat, &rows, &cols)); 4860 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); 4861 /* store row lengths */ 4862 PetscCall(PetscArraycpy(a->ilen, rowlens, M)); 4863 PetscCall(PetscFree(rowlens)); 4864 4865 /* fill in "i" row pointers */ 4866 a->i[0] = 0; 4867 for (i = 0; i < M; i++) a->i[i + 1] = a->i[i] + a->ilen[i]; 4868 /* read in "j" column indices */ 4869 PetscCall(PetscViewerBinaryRead(viewer, a->j, nz, NULL, PETSC_INT)); 4870 /* read in "a" nonzero values */ 4871 PetscCall(PetscViewerBinaryRead(viewer, a->a, nz, NULL, PETSC_SCALAR)); 4872 4873 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 4874 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 4875 PetscFunctionReturn(0); 4876 } 4877 4878 PetscErrorCode MatEqual_SeqAIJ(Mat A, Mat B, PetscBool *flg) { 4879 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data; 4880 const PetscScalar *aa, *ba; 4881 #if defined(PETSC_USE_COMPLEX) 4882 PetscInt k; 4883 #endif 4884 4885 PetscFunctionBegin; 4886 /* If the matrix dimensions are not equal,or no of nonzeros */ 4887 if ((A->rmap->n != B->rmap->n) || (A->cmap->n != B->cmap->n) || (a->nz != b->nz)) { 4888 *flg = PETSC_FALSE; 4889 PetscFunctionReturn(0); 4890 } 4891 4892 /* if the a->i are the same */ 4893 PetscCall(PetscArraycmp(a->i, b->i, A->rmap->n + 1, flg)); 4894 if (!*flg) PetscFunctionReturn(0); 4895 4896 /* if a->j are the same */ 4897 PetscCall(PetscArraycmp(a->j, b->j, a->nz, flg)); 4898 if (!*flg) PetscFunctionReturn(0); 4899 4900 PetscCall(MatSeqAIJGetArrayRead(A, &aa)); 4901 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 4902 /* if a->a are the same */ 4903 #if defined(PETSC_USE_COMPLEX) 4904 for (k = 0; k < a->nz; k++) { 4905 if (PetscRealPart(aa[k]) != PetscRealPart(ba[k]) || PetscImaginaryPart(aa[k]) != PetscImaginaryPart(ba[k])) { 4906 *flg = PETSC_FALSE; 4907 PetscFunctionReturn(0); 4908 } 4909 } 4910 #else 4911 PetscCall(PetscArraycmp(aa, ba, a->nz, flg)); 4912 #endif 4913 PetscCall(MatSeqAIJRestoreArrayRead(A, &aa)); 4914 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 4915 PetscFunctionReturn(0); 4916 } 4917 4918 /*@ 4919 MatCreateSeqAIJWithArrays - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in CSR format) 4920 provided by the user. 4921 4922 Collective 4923 4924 Input Parameters: 4925 + comm - must be an MPI communicator of size 1 4926 . m - number of rows 4927 . n - number of columns 4928 . i - row indices; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix 4929 . j - column indices 4930 - a - matrix values 4931 4932 Output Parameter: 4933 . mat - the matrix 4934 4935 Level: intermediate 4936 4937 Notes: 4938 The i, j, and a arrays are not copied by this routine, the user must free these arrays 4939 once the matrix is destroyed and not before 4940 4941 You cannot set new nonzero locations into this matrix, that will generate an error. 4942 4943 The i and j indices are 0 based 4944 4945 The format which is used for the sparse matrix input, is equivalent to a 4946 row-major ordering.. i.e for the following matrix, the input data expected is 4947 as shown 4948 4949 $ 1 0 0 4950 $ 2 0 3 4951 $ 4 5 6 4952 $ 4953 $ i = {0,1,3,6} [size = nrow+1 = 3+1] 4954 $ j = {0,0,2,0,1,2} [size = 6]; values must be sorted for each row 4955 $ v = {1,2,3,4,5,6} [size = 6] 4956 4957 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateMPIAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()` 4958 @*/ 4959 PetscErrorCode MatCreateSeqAIJWithArrays(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat) { 4960 PetscInt ii; 4961 Mat_SeqAIJ *aij; 4962 PetscInt jj; 4963 4964 PetscFunctionBegin; 4965 PetscCheck(m <= 0 || i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i (row indices) must start with 0"); 4966 PetscCall(MatCreate(comm, mat)); 4967 PetscCall(MatSetSizes(*mat, m, n, m, n)); 4968 /* PetscCall(MatSetBlockSizes(*mat,,)); */ 4969 PetscCall(MatSetType(*mat, MATSEQAIJ)); 4970 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, MAT_SKIP_ALLOCATION, NULL)); 4971 aij = (Mat_SeqAIJ *)(*mat)->data; 4972 PetscCall(PetscMalloc1(m, &aij->imax)); 4973 PetscCall(PetscMalloc1(m, &aij->ilen)); 4974 4975 aij->i = i; 4976 aij->j = j; 4977 aij->a = a; 4978 aij->singlemalloc = PETSC_FALSE; 4979 aij->nonew = -1; /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/ 4980 aij->free_a = PETSC_FALSE; 4981 aij->free_ij = PETSC_FALSE; 4982 4983 for (ii = 0, aij->nonzerorowcnt = 0, aij->rmax = 0; ii < m; ii++) { 4984 aij->ilen[ii] = aij->imax[ii] = i[ii + 1] - i[ii]; 4985 if (PetscDefined(USE_DEBUG)) { 4986 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]); 4987 for (jj = i[ii] + 1; jj < i[ii + 1]; jj++) { 4988 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); 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 identical to previous entry", jj - i[ii], j[jj], ii); 4990 } 4991 } 4992 } 4993 if (PetscDefined(USE_DEBUG)) { 4994 for (ii = 0; ii < aij->i[m]; ii++) { 4995 PetscCheck(j[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]); 4996 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]); 4997 } 4998 } 4999 5000 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5001 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5002 PetscFunctionReturn(0); 5003 } 5004 5005 /*@ 5006 MatCreateSeqAIJFromTriple - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in COO format) 5007 provided by the user. 5008 5009 Collective 5010 5011 Input Parameters: 5012 + comm - must be an MPI communicator of size 1 5013 . m - number of rows 5014 . n - number of columns 5015 . i - row indices 5016 . j - column indices 5017 . a - matrix values 5018 . nz - number of nonzeros 5019 - idx - if the i and j indices start with 1 use `PETSC_TRUE` otherwise use `PETSC_FALSE` 5020 5021 Output Parameter: 5022 . mat - the matrix 5023 5024 Level: intermediate 5025 5026 Example: 5027 For the following matrix, the input data expected is as shown (using 0 based indexing) 5028 .vb 5029 1 0 0 5030 2 0 3 5031 4 5 6 5032 5033 i = {0,1,1,2,2,2} 5034 j = {0,0,2,0,1,2} 5035 v = {1,2,3,4,5,6} 5036 .ve 5037 5038 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateSeqAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`, `MatSetValuesCOO()` 5039 @*/ 5040 PetscErrorCode MatCreateSeqAIJFromTriple(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat, PetscInt nz, PetscBool idx) { 5041 PetscInt ii, *nnz, one = 1, row, col; 5042 5043 PetscFunctionBegin; 5044 PetscCall(PetscCalloc1(m, &nnz)); 5045 for (ii = 0; ii < nz; ii++) nnz[i[ii] - !!idx] += 1; 5046 PetscCall(MatCreate(comm, mat)); 5047 PetscCall(MatSetSizes(*mat, m, n, m, n)); 5048 PetscCall(MatSetType(*mat, MATSEQAIJ)); 5049 PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, 0, nnz)); 5050 for (ii = 0; ii < nz; ii++) { 5051 if (idx) { 5052 row = i[ii] - 1; 5053 col = j[ii] - 1; 5054 } else { 5055 row = i[ii]; 5056 col = j[ii]; 5057 } 5058 PetscCall(MatSetValues(*mat, one, &row, one, &col, &a[ii], ADD_VALUES)); 5059 } 5060 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 5061 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 5062 PetscCall(PetscFree(nnz)); 5063 PetscFunctionReturn(0); 5064 } 5065 5066 PetscErrorCode MatSeqAIJInvalidateDiagonal(Mat A) { 5067 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5068 5069 PetscFunctionBegin; 5070 a->idiagvalid = PETSC_FALSE; 5071 a->ibdiagvalid = PETSC_FALSE; 5072 5073 PetscCall(MatSeqAIJInvalidateDiagonal_Inode(A)); 5074 PetscFunctionReturn(0); 5075 } 5076 5077 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqAIJ(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat) { 5078 PetscFunctionBegin; 5079 PetscCall(MatCreateMPIMatConcatenateSeqMat_MPIAIJ(comm, inmat, n, scall, outmat)); 5080 PetscFunctionReturn(0); 5081 } 5082 5083 /* 5084 Permute A into C's *local* index space using rowemb,colemb. 5085 The embedding are supposed to be injections and the above implies that the range of rowemb is a subset 5086 of [0,m), colemb is in [0,n). 5087 If pattern == DIFFERENT_NONZERO_PATTERN, C is preallocated according to A. 5088 */ 5089 PetscErrorCode MatSetSeqMat_SeqAIJ(Mat C, IS rowemb, IS colemb, MatStructure pattern, Mat B) { 5090 /* If making this function public, change the error returned in this function away from _PLIB. */ 5091 Mat_SeqAIJ *Baij; 5092 PetscBool seqaij; 5093 PetscInt m, n, *nz, i, j, count; 5094 PetscScalar v; 5095 const PetscInt *rowindices, *colindices; 5096 5097 PetscFunctionBegin; 5098 if (!B) PetscFunctionReturn(0); 5099 /* Check to make sure the target matrix (and embeddings) are compatible with C and each other. */ 5100 PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATSEQAIJ, &seqaij)); 5101 PetscCheck(seqaij, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is of wrong type"); 5102 if (rowemb) { 5103 PetscCall(ISGetLocalSize(rowemb, &m)); 5104 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); 5105 } else { 5106 PetscCheck(C->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is row-incompatible with the target matrix"); 5107 } 5108 if (colemb) { 5109 PetscCall(ISGetLocalSize(colemb, &n)); 5110 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); 5111 } else { 5112 PetscCheck(C->cmap->n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is col-incompatible with the target matrix"); 5113 } 5114 5115 Baij = (Mat_SeqAIJ *)(B->data); 5116 if (pattern == DIFFERENT_NONZERO_PATTERN) { 5117 PetscCall(PetscMalloc1(B->rmap->n, &nz)); 5118 for (i = 0; i < B->rmap->n; i++) nz[i] = Baij->i[i + 1] - Baij->i[i]; 5119 PetscCall(MatSeqAIJSetPreallocation(C, 0, nz)); 5120 PetscCall(PetscFree(nz)); 5121 } 5122 if (pattern == SUBSET_NONZERO_PATTERN) PetscCall(MatZeroEntries(C)); 5123 count = 0; 5124 rowindices = NULL; 5125 colindices = NULL; 5126 if (rowemb) PetscCall(ISGetIndices(rowemb, &rowindices)); 5127 if (colemb) PetscCall(ISGetIndices(colemb, &colindices)); 5128 for (i = 0; i < B->rmap->n; i++) { 5129 PetscInt row; 5130 row = i; 5131 if (rowindices) row = rowindices[i]; 5132 for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) { 5133 PetscInt col; 5134 col = Baij->j[count]; 5135 if (colindices) col = colindices[col]; 5136 v = Baij->a[count]; 5137 PetscCall(MatSetValues(C, 1, &row, 1, &col, &v, INSERT_VALUES)); 5138 ++count; 5139 } 5140 } 5141 /* FIXME: set C's nonzerostate correctly. */ 5142 /* Assembly for C is necessary. */ 5143 C->preallocated = PETSC_TRUE; 5144 C->assembled = PETSC_TRUE; 5145 C->was_assembled = PETSC_FALSE; 5146 PetscFunctionReturn(0); 5147 } 5148 5149 PetscFunctionList MatSeqAIJList = NULL; 5150 5151 /*@C 5152 MatSeqAIJSetType - Converts a `MATSEQAIJ` matrix to a subtype 5153 5154 Collective on mat 5155 5156 Input Parameters: 5157 + mat - the matrix object 5158 - matype - matrix type 5159 5160 Options Database Key: 5161 . -mat_seqai_type <method> - for example seqaijcrl 5162 5163 Level: intermediate 5164 5165 .seealso: `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType`, `Mat` 5166 @*/ 5167 PetscErrorCode MatSeqAIJSetType(Mat mat, MatType matype) { 5168 PetscBool sametype; 5169 PetscErrorCode (*r)(Mat, MatType, MatReuse, Mat *); 5170 5171 PetscFunctionBegin; 5172 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 5173 PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype)); 5174 if (sametype) PetscFunctionReturn(0); 5175 5176 PetscCall(PetscFunctionListFind(MatSeqAIJList, matype, &r)); 5177 PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype); 5178 PetscCall((*r)(mat, matype, MAT_INPLACE_MATRIX, &mat)); 5179 PetscFunctionReturn(0); 5180 } 5181 5182 /*@C 5183 MatSeqAIJRegister - - Adds a new sub-matrix type for sequential `MATSEQAIJ` matrices 5184 5185 Not Collective 5186 5187 Input Parameters: 5188 + name - name of a new user-defined matrix type, for example `MATSEQAIJCRL` 5189 - function - routine to convert to subtype 5190 5191 Notes: 5192 `MatSeqAIJRegister()` may be called multiple times to add several user-defined solvers. 5193 5194 Then, your matrix can be chosen with the procedural interface at runtime via the option 5195 $ -mat_seqaij_type my_mat 5196 5197 Level: advanced 5198 5199 .seealso: `MatSeqAIJRegisterAll()` 5200 @*/ 5201 PetscErrorCode MatSeqAIJRegister(const char sname[], PetscErrorCode (*function)(Mat, MatType, MatReuse, Mat *)) { 5202 PetscFunctionBegin; 5203 PetscCall(MatInitializePackage()); 5204 PetscCall(PetscFunctionListAdd(&MatSeqAIJList, sname, function)); 5205 PetscFunctionReturn(0); 5206 } 5207 5208 PetscBool MatSeqAIJRegisterAllCalled = PETSC_FALSE; 5209 5210 /*@C 5211 MatSeqAIJRegisterAll - Registers all of the matrix subtypes of `MATSSEQAIJ` 5212 5213 Not Collective 5214 5215 Level: advanced 5216 5217 .seealso: `MatRegisterAll()`, `MatSeqAIJRegister()` 5218 @*/ 5219 PetscErrorCode MatSeqAIJRegisterAll(void) { 5220 PetscFunctionBegin; 5221 if (MatSeqAIJRegisterAllCalled) PetscFunctionReturn(0); 5222 MatSeqAIJRegisterAllCalled = PETSC_TRUE; 5223 5224 PetscCall(MatSeqAIJRegister(MATSEQAIJCRL, MatConvert_SeqAIJ_SeqAIJCRL)); 5225 PetscCall(MatSeqAIJRegister(MATSEQAIJPERM, MatConvert_SeqAIJ_SeqAIJPERM)); 5226 PetscCall(MatSeqAIJRegister(MATSEQAIJSELL, MatConvert_SeqAIJ_SeqAIJSELL)); 5227 #if defined(PETSC_HAVE_MKL_SPARSE) 5228 PetscCall(MatSeqAIJRegister(MATSEQAIJMKL, MatConvert_SeqAIJ_SeqAIJMKL)); 5229 #endif 5230 #if defined(PETSC_HAVE_CUDA) 5231 PetscCall(MatSeqAIJRegister(MATSEQAIJCUSPARSE, MatConvert_SeqAIJ_SeqAIJCUSPARSE)); 5232 #endif 5233 #if defined(PETSC_HAVE_KOKKOS_KERNELS) 5234 PetscCall(MatSeqAIJRegister(MATSEQAIJKOKKOS, MatConvert_SeqAIJ_SeqAIJKokkos)); 5235 #endif 5236 #if defined(PETSC_HAVE_VIENNACL) && defined(PETSC_HAVE_VIENNACL_NO_CUDA) 5237 PetscCall(MatSeqAIJRegister(MATMPIAIJVIENNACL, MatConvert_SeqAIJ_SeqAIJViennaCL)); 5238 #endif 5239 PetscFunctionReturn(0); 5240 } 5241 5242 /* 5243 Special version for direct calls from Fortran 5244 */ 5245 #include <petsc/private/fortranimpl.h> 5246 #if defined(PETSC_HAVE_FORTRAN_CAPS) 5247 #define matsetvaluesseqaij_ MATSETVALUESSEQAIJ 5248 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 5249 #define matsetvaluesseqaij_ matsetvaluesseqaij 5250 #endif 5251 5252 /* Change these macros so can be used in void function */ 5253 5254 /* Change these macros so can be used in void function */ 5255 /* Identical to PetscCallVoid, except it assigns to *_ierr */ 5256 #undef PetscCall 5257 #define PetscCall(...) \ 5258 do { \ 5259 PetscErrorCode ierr_msv_mpiaij = __VA_ARGS__; \ 5260 if (PetscUnlikely(ierr_msv_mpiaij)) { \ 5261 *_ierr = PetscError(PETSC_COMM_SELF, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr_msv_mpiaij, PETSC_ERROR_REPEAT, " "); \ 5262 return; \ 5263 } \ 5264 } while (0) 5265 5266 #undef SETERRQ 5267 #define SETERRQ(comm, ierr, ...) \ 5268 do { \ 5269 *_ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr, PETSC_ERROR_INITIAL, __VA_ARGS__); \ 5270 return; \ 5271 } while (0) 5272 5273 PETSC_EXTERN void matsetvaluesseqaij_(Mat *AA, PetscInt *mm, const PetscInt im[], PetscInt *nn, const PetscInt in[], const PetscScalar v[], InsertMode *isis, PetscErrorCode *_ierr) { 5274 Mat A = *AA; 5275 PetscInt m = *mm, n = *nn; 5276 InsertMode is = *isis; 5277 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 5278 PetscInt *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N; 5279 PetscInt *imax, *ai, *ailen; 5280 PetscInt *aj, nonew = a->nonew, lastcol = -1; 5281 MatScalar *ap, value, *aa; 5282 PetscBool ignorezeroentries = a->ignorezeroentries; 5283 PetscBool roworiented = a->roworiented; 5284 5285 PetscFunctionBegin; 5286 MatCheckPreallocated(A, 1); 5287 imax = a->imax; 5288 ai = a->i; 5289 ailen = a->ilen; 5290 aj = a->j; 5291 aa = a->a; 5292 5293 for (k = 0; k < m; k++) { /* loop over added rows */ 5294 row = im[k]; 5295 if (row < 0) continue; 5296 PetscCheck(row < A->rmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large"); 5297 rp = aj + ai[row]; 5298 ap = aa + ai[row]; 5299 rmax = imax[row]; 5300 nrow = ailen[row]; 5301 low = 0; 5302 high = nrow; 5303 for (l = 0; l < n; l++) { /* loop over added columns */ 5304 if (in[l] < 0) continue; 5305 PetscCheck(in[l] < A->cmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Column too large"); 5306 col = in[l]; 5307 if (roworiented) value = v[l + k * n]; 5308 else value = v[k + l * m]; 5309 5310 if (value == 0.0 && ignorezeroentries && (is == ADD_VALUES)) continue; 5311 5312 if (col <= lastcol) low = 0; 5313 else high = nrow; 5314 lastcol = col; 5315 while (high - low > 5) { 5316 t = (low + high) / 2; 5317 if (rp[t] > col) high = t; 5318 else low = t; 5319 } 5320 for (i = low; i < high; i++) { 5321 if (rp[i] > col) break; 5322 if (rp[i] == col) { 5323 if (is == ADD_VALUES) ap[i] += value; 5324 else ap[i] = value; 5325 goto noinsert; 5326 } 5327 } 5328 if (value == 0.0 && ignorezeroentries) goto noinsert; 5329 if (nonew == 1) goto noinsert; 5330 PetscCheck(nonew != -1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero in the matrix"); 5331 MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar); 5332 N = nrow++ - 1; 5333 a->nz++; 5334 high++; 5335 /* shift up all the later entries in this row */ 5336 for (ii = N; ii >= i; ii--) { 5337 rp[ii + 1] = rp[ii]; 5338 ap[ii + 1] = ap[ii]; 5339 } 5340 rp[i] = col; 5341 ap[i] = value; 5342 A->nonzerostate++; 5343 noinsert:; 5344 low = i + 1; 5345 } 5346 ailen[row] = nrow; 5347 } 5348 PetscFunctionReturnVoid(); 5349 } 5350 /* Undefining these here since they were redefined from their original definition above! No 5351 * other PETSc functions should be defined past this point, as it is impossible to recover the 5352 * original definitions */ 5353 #undef PetscCall 5354 #undef SETERRQ 5355