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