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