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