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