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