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