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