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