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