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