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