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