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