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