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