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