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