1 #ifndef lint 2 static char vcid[] = "$Id: aij.c,v 1.150 1996/02/16 20:05:38 balay Exp curfman $"; 3 #endif 4 5 /* 6 Defines the basic matrix operations for the AIJ (compressed row) 7 matrix storage format. 8 */ 9 #include "aij.h" 10 #include "vec/vecimpl.h" 11 #include "inline/spops.h" 12 #include "petsc.h" 13 #include "inline/bitarray.h" 14 15 extern int MatToSymmetricIJ_SeqAIJ(int,int*,int*,int,int**,int**); 16 17 static int MatGetReordering_SeqAIJ(Mat A,MatOrdering type,IS *rperm, IS *cperm) 18 { 19 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 20 int ierr, *ia, *ja,n,*idx,i; 21 /*Viewer V1, V2;*/ 22 23 /* 24 this is tacky: In the future when we have written special factorization 25 and solve routines for the identity permutation we should use a 26 stride index set instead of the general one. 27 */ 28 if (type == ORDER_NATURAL) { 29 n = a->n; 30 idx = (int *) PetscMalloc( n*sizeof(int) ); CHKPTRQ(idx); 31 for ( i=0; i<n; i++ ) idx[i] = i; 32 ierr = ISCreateSeq(MPI_COMM_SELF,n,idx,rperm); CHKERRQ(ierr); 33 ierr = ISCreateSeq(MPI_COMM_SELF,n,idx,cperm); CHKERRQ(ierr); 34 PetscFree(idx); 35 ISSetPermutation(*rperm); 36 ISSetPermutation(*cperm); 37 ISSetIdentity(*rperm); 38 ISSetIdentity(*cperm); 39 return 0; 40 } 41 42 ierr = MatToSymmetricIJ_SeqAIJ(a->n,a->i,a->j,a->indexshift, &ia, &ja);CHKERRQ(ierr); 43 ierr = MatGetReordering_IJ(a->n,ia,ja,type,rperm,cperm); CHKERRQ(ierr); 44 45 PetscFree(ia); PetscFree(ja); 46 return 0; 47 } 48 49 #define CHUNKSIZE 15 50 51 /* This version has row oriented v */ 52 static int MatSetValues_SeqAIJ(Mat A,int m,int *im,int n,int *in,Scalar *v,InsertMode is) 53 { 54 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 55 int *rp,k,low,high,t,ii,row,nrow,i,col,l,rmax, N, sorted = a->sorted; 56 int *imax = a->imax, *ai = a->i, *ailen = a->ilen,roworiented = a->roworiented; 57 int *aj = a->j, nonew = a->nonew,shift = a->indexshift; 58 Scalar *ap,value, *aa = a->a; 59 60 for ( k=0; k<m; k++ ) { /* loop over added rows */ 61 row = im[k]; 62 if (row < 0) SETERRQ(1,"MatSetValues_SeqAIJ:Negative row"); 63 if (row >= a->m) SETERRQ(1,"MatSetValues_SeqAIJ:Row too large"); 64 rp = aj + ai[row] + shift; ap = aa + ai[row] + shift; 65 rmax = imax[row]; nrow = ailen[row]; 66 low = 0; 67 for ( l=0; l<n; l++ ) { /* loop over added columns */ 68 if (in[l] < 0) SETERRQ(1,"MatSetValues_SeqAIJ:Negative column"); 69 if (in[l] >= a->n) SETERRQ(1,"MatSetValues_SeqAIJ:Column too large"); 70 col = in[l] - shift; 71 if (roworiented) { 72 value = *v++; 73 } 74 else { 75 value = v[k + l*m]; 76 } 77 if (!sorted) low = 0; high = nrow; 78 while (high-low > 5) { 79 t = (low+high)/2; 80 if (rp[t] > col) high = t; 81 else low = t; 82 } 83 for ( i=low; i<high; i++ ) { 84 if (rp[i] > col) break; 85 if (rp[i] == col) { 86 if (is == ADD_VALUES) ap[i] += value; 87 else ap[i] = value; 88 goto noinsert; 89 } 90 } 91 if (nonew) goto noinsert; 92 if (nrow >= rmax) { 93 /* there is no extra room in row, therefore enlarge */ 94 int new_nz = ai[a->m] + CHUNKSIZE,len,*new_i,*new_j; 95 Scalar *new_a; 96 97 /* malloc new storage space */ 98 len = new_nz*(sizeof(int)+sizeof(Scalar))+(a->m+1)*sizeof(int); 99 new_a = (Scalar *) PetscMalloc( len ); CHKPTRQ(new_a); 100 new_j = (int *) (new_a + new_nz); 101 new_i = new_j + new_nz; 102 103 /* copy over old data into new slots */ 104 for ( ii=0; ii<row+1; ii++ ) {new_i[ii] = ai[ii];} 105 for ( ii=row+1; ii<a->m+1; ii++ ) {new_i[ii] = ai[ii]+CHUNKSIZE;} 106 PetscMemcpy(new_j,aj,(ai[row]+nrow+shift)*sizeof(int)); 107 len = (new_nz - CHUNKSIZE - ai[row] - nrow - shift); 108 PetscMemcpy(new_j+ai[row]+shift+nrow+CHUNKSIZE,aj+ai[row]+shift+nrow, 109 len*sizeof(int)); 110 PetscMemcpy(new_a,aa,(ai[row]+nrow+shift)*sizeof(Scalar)); 111 PetscMemcpy(new_a+ai[row]+shift+nrow+CHUNKSIZE,aa+ai[row]+shift+nrow, 112 len*sizeof(Scalar)); 113 /* free up old matrix storage */ 114 PetscFree(a->a); 115 if (!a->singlemalloc) {PetscFree(a->i);PetscFree(a->j);} 116 aa = a->a = new_a; ai = a->i = new_i; aj = a->j = new_j; 117 a->singlemalloc = 1; 118 119 rp = aj + ai[row] + shift; ap = aa + ai[row] + shift; 120 rmax = imax[row] = imax[row] + CHUNKSIZE; 121 PLogObjectMemory(A,CHUNKSIZE*(sizeof(int) + sizeof(Scalar))); 122 a->maxnz += CHUNKSIZE; 123 a->reallocs++; 124 } 125 N = nrow++ - 1; a->nz++; 126 /* shift up all the later entries in this row */ 127 for ( ii=N; ii>=i; ii-- ) { 128 rp[ii+1] = rp[ii]; 129 ap[ii+1] = ap[ii]; 130 } 131 rp[i] = col; 132 ap[i] = value; 133 noinsert:; 134 low = i + 1; 135 } 136 ailen[row] = nrow; 137 } 138 return 0; 139 } 140 141 static int MatGetValues_SeqAIJ(Mat A,int m,int *im,int n,int *in,Scalar *v) 142 { 143 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 144 int *rp, k, low, high, t, row, nrow, i, col, l, *aj = a->j; 145 int *ai = a->i, *ailen = a->ilen, shift = a->indexshift; 146 Scalar *ap, *aa = a->a, zero = 0.0; 147 148 for ( k=0; k<m; k++ ) { /* loop over rows */ 149 row = im[k]; 150 if (row < 0) SETERRQ(1,"MatGetValues_SeqAIJ:Negative row"); 151 if (row >= a->m) SETERRQ(1,"MatGetValues_SeqAIJ:Row too large"); 152 rp = aj + ai[row] + shift; ap = aa + ai[row] + shift; 153 nrow = ailen[row]; 154 for ( l=0; l<n; l++ ) { /* loop over columns */ 155 if (in[l] < 0) SETERRQ(1,"MatGetValues_SeqAIJ:Negative column"); 156 if (in[l] >= a->n) SETERRQ(1,"MatGetValues_SeqAIJ:Column too large"); 157 col = in[l] - shift; 158 high = nrow; low = 0; /* assume unsorted */ 159 while (high-low > 5) { 160 t = (low+high)/2; 161 if (rp[t] > col) high = t; 162 else low = t; 163 } 164 for ( i=low; i<high; i++ ) { 165 if (rp[i] > col) break; 166 if (rp[i] == col) { 167 *v++ = ap[i]; 168 goto finished; 169 } 170 } 171 *v++ = zero; 172 finished:; 173 } 174 } 175 return 0; 176 } 177 178 #include "draw.h" 179 #include "pinclude/pviewer.h" 180 #include "sysio.h" 181 182 static int MatView_SeqAIJ_Binary(Mat A,Viewer viewer) 183 { 184 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 185 int i, fd, *col_lens, ierr; 186 187 ierr = ViewerFileGetDescriptor_Private(viewer,&fd); CHKERRQ(ierr); 188 col_lens = (int *) PetscMalloc( (4+a->m)*sizeof(int) ); CHKPTRQ(col_lens); 189 col_lens[0] = MAT_COOKIE; 190 col_lens[1] = a->m; 191 col_lens[2] = a->n; 192 col_lens[3] = a->nz; 193 194 /* store lengths of each row and write (including header) to file */ 195 for ( i=0; i<a->m; i++ ) { 196 col_lens[4+i] = a->i[i+1] - a->i[i]; 197 } 198 ierr = SYWrite(fd,col_lens,4+a->m,SYINT,1); CHKERRQ(ierr); 199 PetscFree(col_lens); 200 201 /* store column indices (zero start index) */ 202 if (a->indexshift) { 203 for ( i=0; i<a->nz; i++ ) a->j[i]--; 204 } 205 ierr = SYWrite(fd,a->j,a->nz,SYINT,0); CHKERRQ(ierr); 206 if (a->indexshift) { 207 for ( i=0; i<a->nz; i++ ) a->j[i]++; 208 } 209 210 /* store nonzero values */ 211 ierr = SYWrite(fd,a->a,a->nz,SYSCALAR,0); CHKERRQ(ierr); 212 return 0; 213 } 214 215 static int MatView_SeqAIJ_ASCII(Mat A,Viewer viewer) 216 { 217 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 218 int ierr, i,j, m = a->m, shift = a->indexshift, format, flg; 219 FILE *fd; 220 char *outputname; 221 222 ierr = ViewerFileGetPointer(viewer,&fd); CHKERRQ(ierr); 223 ierr = ViewerFileGetOutputname_Private(viewer,&outputname); CHKERRQ(ierr); 224 ierr = ViewerFileGetFormat_Private(viewer,&format); 225 if (format == FILE_FORMAT_INFO) { 226 return 0; 227 } 228 else if (format == FILE_FORMAT_INFO_DETAILED) { 229 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_no_inode",&flg); CHKERRQ(ierr); 230 if (flg) fprintf(fd," not using I-node routines\n"); 231 else fprintf(fd," using I-node routines: found %d nodes, limit used is %d\n", 232 a->inode.node_count,a->inode.limit); 233 } 234 else if (format == FILE_FORMAT_MATLAB) { 235 int nz, nzalloc, mem; 236 MatGetInfo(A,MAT_LOCAL,&nz,&nzalloc,&mem); 237 fprintf(fd,"%% Size = %d %d \n",m,a->n); 238 fprintf(fd,"%% Nonzeros = %d \n",nz); 239 fprintf(fd,"zzz = zeros(%d,3);\n",nz); 240 fprintf(fd,"zzz = [\n"); 241 242 for (i=0; i<m; i++) { 243 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 244 #if defined(PETSC_COMPLEX) 245 fprintf(fd,"%d %d %18.16e %18.16e \n",i+1,a->j[j]+!shift,real(a->a[j]), 246 imag(a->a[j])); 247 #else 248 fprintf(fd,"%d %d %18.16e\n", i+1, a->j[j]+!shift, a->a[j]); 249 #endif 250 } 251 } 252 fprintf(fd,"];\n %s = spconvert(zzz);\n",outputname); 253 } 254 else { 255 for ( i=0; i<m; i++ ) { 256 fprintf(fd,"row %d:",i); 257 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 258 #if defined(PETSC_COMPLEX) 259 if (imag(a->a[j]) != 0.0) { 260 fprintf(fd," %d %g + %g i",a->j[j]+shift,real(a->a[j]),imag(a->a[j])); 261 } 262 else { 263 fprintf(fd," %d %g ",a->j[j]+shift,real(a->a[j])); 264 } 265 #else 266 fprintf(fd," %d %g ",a->j[j]+shift,a->a[j]); 267 #endif 268 } 269 fprintf(fd,"\n"); 270 } 271 } 272 fflush(fd); 273 return 0; 274 } 275 276 static int MatView_SeqAIJ_Draw(Mat A,Viewer viewer) 277 { 278 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 279 int ierr, i,j, m = a->m, shift = a->indexshift,pause,color; 280 double xl,yl,xr,yr,w,h,xc,yc,scale = 1.0,x_l,x_r,y_l,y_r; 281 Draw draw = (Draw) viewer; 282 DrawButton button; 283 284 xr = a->n; yr = a->m; h = yr/10.0; w = xr/10.0; 285 xr += w; yr += h; xl = -w; yl = -h; 286 ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr); 287 /* loop over matrix elements drawing boxes */ 288 color = DRAW_BLUE; 289 for ( i=0; i<m; i++ ) { 290 y_l = m - i - 1.0; y_r = y_l + 1.0; 291 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 292 x_l = a->j[j] + shift; x_r = x_l + 1.0; 293 #if defined(PETSC_COMPLEX) 294 if (real(a->a[j]) >= 0.) continue; 295 #else 296 if (a->a[j] >= 0.) continue; 297 #endif 298 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 299 } 300 } 301 color = DRAW_CYAN; 302 for ( i=0; i<m; i++ ) { 303 y_l = m - i - 1.0; y_r = y_l + 1.0; 304 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 305 x_l = a->j[j] + shift; x_r = x_l + 1.0; 306 if (a->a[j] != 0.) continue; 307 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 308 } 309 } 310 color = DRAW_RED; 311 for ( i=0; i<m; i++ ) { 312 y_l = m - i - 1.0; y_r = y_l + 1.0; 313 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 314 x_l = a->j[j] + shift; x_r = x_l + 1.0; 315 #if defined(PETSC_COMPLEX) 316 if (real(a->a[j]) <= 0.) continue; 317 #else 318 if (a->a[j] <= 0.) continue; 319 #endif 320 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 321 } 322 } 323 DrawFlush(draw); 324 DrawGetPause(draw,&pause); 325 if (pause >= 0) { PetscSleep(pause); return 0;} 326 327 /* allow the matrix to zoom or shrink */ 328 ierr = DrawGetMouseButton(draw,&button,&xc,&yc,0,0); 329 while (button != BUTTON_RIGHT) { 330 DrawClear(draw); 331 if (button == BUTTON_LEFT) scale = .5; 332 else if (button == BUTTON_CENTER) scale = 2.; 333 xl = scale*(xl + w - xc) + xc - w*scale; 334 xr = scale*(xr - w - xc) + xc + w*scale; 335 yl = scale*(yl + h - yc) + yc - h*scale; 336 yr = scale*(yr - h - yc) + yc + h*scale; 337 w *= scale; h *= scale; 338 ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr); 339 color = DRAW_BLUE; 340 for ( i=0; i<m; i++ ) { 341 y_l = m - i - 1.0; y_r = y_l + 1.0; 342 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 343 x_l = a->j[j] + shift; x_r = x_l + 1.0; 344 #if defined(PETSC_COMPLEX) 345 if (real(a->a[j]) >= 0.) continue; 346 #else 347 if (a->a[j] >= 0.) continue; 348 #endif 349 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 350 } 351 } 352 color = DRAW_CYAN; 353 for ( i=0; i<m; i++ ) { 354 y_l = m - i - 1.0; y_r = y_l + 1.0; 355 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 356 x_l = a->j[j] + shift; x_r = x_l + 1.0; 357 if (a->a[j] != 0.) continue; 358 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 359 } 360 } 361 color = DRAW_RED; 362 for ( i=0; i<m; i++ ) { 363 y_l = m - i - 1.0; y_r = y_l + 1.0; 364 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 365 x_l = a->j[j] + shift; x_r = x_l + 1.0; 366 #if defined(PETSC_COMPLEX) 367 if (real(a->a[j]) <= 0.) continue; 368 #else 369 if (a->a[j] <= 0.) continue; 370 #endif 371 DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color); 372 } 373 } 374 ierr = DrawGetMouseButton(draw,&button,&xc,&yc,0,0); 375 } 376 return 0; 377 } 378 379 static int MatView_SeqAIJ(PetscObject obj,Viewer viewer) 380 { 381 Mat A = (Mat) obj; 382 Mat_SeqAIJ *a = (Mat_SeqAIJ*) A->data; 383 PetscObject vobj = (PetscObject) viewer; 384 385 if (!viewer) { 386 viewer = STDOUT_VIEWER_SELF; vobj = (PetscObject) viewer; 387 } 388 if (vobj->cookie == VIEWER_COOKIE) { 389 if (vobj->type == MATLAB_VIEWER) { 390 return ViewerMatlabPutSparse_Private(viewer,a->m,a->n,a->nz,a->a,a->i,a->j); 391 } 392 else if (vobj->type == ASCII_FILE_VIEWER || vobj->type == ASCII_FILES_VIEWER){ 393 return MatView_SeqAIJ_ASCII(A,viewer); 394 } 395 else if (vobj->type == BINARY_FILE_VIEWER) { 396 return MatView_SeqAIJ_Binary(A,viewer); 397 } 398 } 399 else if (vobj->cookie == DRAW_COOKIE) { 400 if (vobj->type == NULLWINDOW) return 0; 401 else return MatView_SeqAIJ_Draw(A,viewer); 402 } 403 return 0; 404 } 405 extern int Mat_AIJ_CheckInode(Mat); 406 static int MatAssemblyEnd_SeqAIJ(Mat A,MatAssemblyType mode) 407 { 408 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 409 int fshift = 0,i,j,*ai = a->i, *aj = a->j, *imax = a->imax,ierr; 410 int m = a->m, *ip, N, *ailen = a->ilen,shift = a->indexshift; 411 Scalar *aa = a->a, *ap; 412 413 if (mode == FLUSH_ASSEMBLY) return 0; 414 415 for ( i=1; i<m; i++ ) { 416 /* move each row back by the amount of empty slots (fshift) before it*/ 417 fshift += imax[i-1] - ailen[i-1]; 418 if (fshift) { 419 ip = aj + ai[i] + shift; ap = aa + ai[i] + shift; 420 N = ailen[i]; 421 for ( j=0; j<N; j++ ) { 422 ip[j-fshift] = ip[j]; 423 ap[j-fshift] = ap[j]; 424 } 425 } 426 ai[i] = ai[i-1] + ailen[i-1]; 427 } 428 if (m) { 429 fshift += imax[m-1] - ailen[m-1]; 430 ai[m] = ai[m-1] + ailen[m-1]; 431 } 432 /* reset ilen and imax for each row */ 433 for ( i=0; i<m; i++ ) { 434 ailen[i] = imax[i] = ai[i+1] - ai[i]; 435 } 436 a->nz = ai[m] + shift; 437 438 /* diagonals may have moved, so kill the diagonal pointers */ 439 if (fshift && a->diag) { 440 PetscFree(a->diag); 441 PLogObjectMemory(A,-(m+1)*sizeof(int)); 442 a->diag = 0; 443 } 444 PLogInfo((PetscObject)A,"MatAssemblyEnd_SeqAIJ:Unneeded storage space %d used %d rows %d\n", 445 fshift,a->nz,m); 446 PLogInfo((PetscObject)A,"MatAssemblyEnd_SeqAIJ:Number of mallocs during MatSetValues %d\n", 447 a->reallocs); 448 /* check out for identical nodes. If found, use inode functions */ 449 ierr = Mat_AIJ_CheckInode(A); CHKERRQ(ierr); 450 return 0; 451 } 452 453 static int MatZeroEntries_SeqAIJ(Mat A) 454 { 455 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 456 PetscMemzero(a->a,(a->i[a->m]+a->indexshift)*sizeof(Scalar)); 457 return 0; 458 } 459 460 int MatDestroy_SeqAIJ(PetscObject obj) 461 { 462 Mat A = (Mat) obj; 463 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 464 465 #if defined(PETSC_LOG) 466 PLogObjectState(obj,"Rows=%d, Cols=%d, NZ=%d",a->m,a->n,a->nz); 467 #endif 468 PetscFree(a->a); 469 if (!a->singlemalloc) { PetscFree(a->i); PetscFree(a->j);} 470 if (a->diag) PetscFree(a->diag); 471 if (a->ilen) PetscFree(a->ilen); 472 if (a->imax) PetscFree(a->imax); 473 if (a->solve_work) PetscFree(a->solve_work); 474 if (a->inode.size) PetscFree(a->inode.size); 475 PetscFree(a); 476 PLogObjectDestroy(A); 477 PetscHeaderDestroy(A); 478 return 0; 479 } 480 481 static int MatCompress_SeqAIJ(Mat A) 482 { 483 return 0; 484 } 485 486 static int MatSetOption_SeqAIJ(Mat A,MatOption op) 487 { 488 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 489 if (op == ROW_ORIENTED) a->roworiented = 1; 490 else if (op == COLUMN_ORIENTED) a->roworiented = 0; 491 else if (op == COLUMNS_SORTED) a->sorted = 1; 492 else if (op == NO_NEW_NONZERO_LOCATIONS) a->nonew = 1; 493 else if (op == YES_NEW_NONZERO_LOCATIONS) a->nonew = 0; 494 else if (op == ROWS_SORTED || 495 op == SYMMETRIC_MATRIX || 496 op == STRUCTURALLY_SYMMETRIC_MATRIX || 497 op == YES_NEW_DIAGONALS) 498 PLogInfo((PetscObject)A,"Info:MatSetOption_SeqAIJ:Option ignored\n"); 499 else if (op == NO_NEW_DIAGONALS) 500 {SETERRQ(PETSC_ERR_SUP,"MatSetOption_SeqAIJ:NO_NEW_DIAGONALS");} 501 else if (op == INODE_LIMIT_1) a->inode.limit = 1; 502 else if (op == INODE_LIMIT_2) a->inode.limit = 2; 503 else if (op == INODE_LIMIT_3) a->inode.limit = 3; 504 else if (op == INODE_LIMIT_4) a->inode.limit = 4; 505 else if (op == INODE_LIMIT_5) a->inode.limit = 5; 506 else 507 {SETERRQ(PETSC_ERR_SUP,"MatSetOption_SeqAIJ:unknown option");} 508 return 0; 509 } 510 511 static int MatGetDiagonal_SeqAIJ(Mat A,Vec v) 512 { 513 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 514 int i,j, n,shift = a->indexshift; 515 Scalar *x, zero = 0.0; 516 517 VecSet(&zero,v); 518 VecGetArray(v,&x); VecGetLocalSize(v,&n); 519 if (n != a->m) SETERRQ(1,"MatGetDiagonal_SeqAIJ:Nonconforming matrix and vector"); 520 for ( i=0; i<a->m; i++ ) { 521 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 522 if (a->j[j]+shift == i) { 523 x[i] = a->a[j]; 524 break; 525 } 526 } 527 } 528 return 0; 529 } 530 531 /* -------------------------------------------------------*/ 532 /* Should check that shapes of vectors and matrices match */ 533 /* -------------------------------------------------------*/ 534 static int MatMultTrans_SeqAIJ(Mat A,Vec xx,Vec yy) 535 { 536 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 537 Scalar *x, *y, *v, alpha; 538 int m = a->m, n, i, *idx, shift = a->indexshift; 539 540 VecGetArray(xx,&x); VecGetArray(yy,&y); 541 PetscMemzero(y,a->n*sizeof(Scalar)); 542 y = y + shift; /* shift for Fortran start by 1 indexing */ 543 for ( i=0; i<m; i++ ) { 544 idx = a->j + a->i[i] + shift; 545 v = a->a + a->i[i] + shift; 546 n = a->i[i+1] - a->i[i]; 547 alpha = x[i]; 548 while (n-->0) {y[*idx++] += alpha * *v++;} 549 } 550 PLogFlops(2*a->nz - a->n); 551 return 0; 552 } 553 554 static int MatMultTransAdd_SeqAIJ(Mat A,Vec xx,Vec zz,Vec yy) 555 { 556 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 557 Scalar *x, *y, *v, alpha; 558 int m = a->m, n, i, *idx,shift = a->indexshift; 559 560 VecGetArray(xx,&x); VecGetArray(yy,&y); 561 if (zz != yy) VecCopy(zz,yy); 562 y = y + shift; /* shift for Fortran start by 1 indexing */ 563 for ( i=0; i<m; i++ ) { 564 idx = a->j + a->i[i] + shift; 565 v = a->a + a->i[i] + shift; 566 n = a->i[i+1] - a->i[i]; 567 alpha = x[i]; 568 while (n-->0) {y[*idx++] += alpha * *v++;} 569 } 570 return 0; 571 } 572 573 static int MatMult_SeqAIJ(Mat A,Vec xx,Vec yy) 574 { 575 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 576 Scalar *x, *y, *v, sum; 577 int m = a->m, n, i, *idx, shift = a->indexshift,*ii; 578 579 VecGetArray(xx,&x); VecGetArray(yy,&y); 580 x = x + shift; /* shift for Fortran start by 1 indexing */ 581 idx = a->j; 582 v = a->a; 583 ii = a->i; 584 for ( i=0; i<m; i++ ) { 585 n = ii[1] - ii[0]; ii++; 586 sum = 0.0; 587 /* SPARSEDENSEDOT(sum,x,v,idx,n); */ 588 /* for ( j=n-1; j>-1; j--) sum += v[j]*x[idx[j]]; */ 589 while (n--) sum += *v++ * x[*idx++]; 590 y[i] = sum; 591 } 592 PLogFlops(2*a->nz - m); 593 return 0; 594 } 595 596 static int MatMultAdd_SeqAIJ(Mat A,Vec xx,Vec yy,Vec zz) 597 { 598 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 599 Scalar *x, *y, *z, *v, sum; 600 int m = a->m, n, i, *idx, shift = a->indexshift,*ii; 601 602 VecGetArray(xx,&x); VecGetArray(yy,&y); VecGetArray(zz,&z); 603 x = x + shift; /* shift for Fortran start by 1 indexing */ 604 idx = a->j; 605 v = a->a; 606 ii = a->i; 607 for ( i=0; i<m; i++ ) { 608 n = ii[1] - ii[0]; ii++; 609 sum = y[i]; 610 /* SPARSEDENSEDOT(sum,x,v,idx,n); */ 611 while (n--) sum += *v++ * x[*idx++]; 612 z[i] = sum; 613 } 614 PLogFlops(2*a->nz); 615 return 0; 616 } 617 618 /* 619 Adds diagonal pointers to sparse matrix structure. 620 */ 621 622 int MatMarkDiag_SeqAIJ(Mat A) 623 { 624 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 625 int i,j, *diag, m = a->m,shift = a->indexshift; 626 627 diag = (int *) PetscMalloc( (m+1)*sizeof(int)); CHKPTRQ(diag); 628 PLogObjectMemory(A,(m+1)*sizeof(int)); 629 for ( i=0; i<a->m; i++ ) { 630 for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) { 631 if (a->j[j]+shift == i) { 632 diag[i] = j - shift; 633 break; 634 } 635 } 636 } 637 a->diag = diag; 638 return 0; 639 } 640 641 static int MatRelax_SeqAIJ(Mat A,Vec bb,double omega,MatSORType flag, 642 double fshift,int its,Vec xx) 643 { 644 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 645 Scalar *x, *b, *bs, d, *xs, sum, *v = a->a,*t,scale,*ts, *xb; 646 int ierr, *idx, *diag,n = a->n, m = a->m, i, shift = a->indexshift; 647 648 VecGetArray(xx,&x); VecGetArray(bb,&b); 649 if (!a->diag) {if ((ierr = MatMarkDiag_SeqAIJ(A))) return ierr;} 650 diag = a->diag; 651 xs = x + shift; /* shifted by one for index start of a or a->j*/ 652 if (flag == SOR_APPLY_UPPER) { 653 /* apply ( U + D/omega) to the vector */ 654 bs = b + shift; 655 for ( i=0; i<m; i++ ) { 656 d = fshift + a->a[diag[i] + shift]; 657 n = a->i[i+1] - diag[i] - 1; 658 idx = a->j + diag[i] + (!shift); 659 v = a->a + diag[i] + (!shift); 660 sum = b[i]*d/omega; 661 SPARSEDENSEDOT(sum,bs,v,idx,n); 662 x[i] = sum; 663 } 664 return 0; 665 } 666 if (flag == SOR_APPLY_LOWER) { 667 SETERRQ(1,"MatRelax_SeqAIJ:SOR_APPLY_LOWER is not done"); 668 } 669 else if (flag & SOR_EISENSTAT) { 670 /* Let A = L + U + D; where L is lower trianglar, 671 U is upper triangular, E is diagonal; This routine applies 672 673 (L + E)^{-1} A (U + E)^{-1} 674 675 to a vector efficiently using Eisenstat's trick. This is for 676 the case of SSOR preconditioner, so E is D/omega where omega 677 is the relaxation factor. 678 */ 679 t = (Scalar *) PetscMalloc( m*sizeof(Scalar) ); CHKPTRQ(t); 680 scale = (2.0/omega) - 1.0; 681 682 /* x = (E + U)^{-1} b */ 683 for ( i=m-1; i>=0; i-- ) { 684 d = fshift + a->a[diag[i] + shift]; 685 n = a->i[i+1] - diag[i] - 1; 686 idx = a->j + diag[i] + (!shift); 687 v = a->a + diag[i] + (!shift); 688 sum = b[i]; 689 SPARSEDENSEMDOT(sum,xs,v,idx,n); 690 x[i] = omega*(sum/d); 691 } 692 693 /* t = b - (2*E - D)x */ 694 v = a->a; 695 for ( i=0; i<m; i++ ) { t[i] = b[i] - scale*(v[*diag++ + shift])*x[i]; } 696 697 /* t = (E + L)^{-1}t */ 698 ts = t + shift; /* shifted by one for index start of a or a->j*/ 699 diag = a->diag; 700 for ( i=0; i<m; i++ ) { 701 d = fshift + a->a[diag[i]+shift]; 702 n = diag[i] - a->i[i]; 703 idx = a->j + a->i[i] + shift; 704 v = a->a + a->i[i] + shift; 705 sum = t[i]; 706 SPARSEDENSEMDOT(sum,ts,v,idx,n); 707 t[i] = omega*(sum/d); 708 } 709 710 /* x = x + t */ 711 for ( i=0; i<m; i++ ) { x[i] += t[i]; } 712 PetscFree(t); 713 return 0; 714 } 715 if (flag & SOR_ZERO_INITIAL_GUESS) { 716 if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){ 717 for ( i=0; i<m; i++ ) { 718 d = fshift + a->a[diag[i]+shift]; 719 n = diag[i] - a->i[i]; 720 idx = a->j + a->i[i] + shift; 721 v = a->a + a->i[i] + shift; 722 sum = b[i]; 723 SPARSEDENSEMDOT(sum,xs,v,idx,n); 724 x[i] = omega*(sum/d); 725 } 726 xb = x; 727 } 728 else xb = b; 729 if ((flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) && 730 (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP)) { 731 for ( i=0; i<m; i++ ) { 732 x[i] *= a->a[diag[i]+shift]; 733 } 734 } 735 if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){ 736 for ( i=m-1; i>=0; i-- ) { 737 d = fshift + a->a[diag[i] + shift]; 738 n = a->i[i+1] - diag[i] - 1; 739 idx = a->j + diag[i] + (!shift); 740 v = a->a + diag[i] + (!shift); 741 sum = xb[i]; 742 SPARSEDENSEMDOT(sum,xs,v,idx,n); 743 x[i] = omega*(sum/d); 744 } 745 } 746 its--; 747 } 748 while (its--) { 749 if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){ 750 for ( i=0; i<m; i++ ) { 751 d = fshift + a->a[diag[i]+shift]; 752 n = a->i[i+1] - a->i[i]; 753 idx = a->j + a->i[i] + shift; 754 v = a->a + a->i[i] + shift; 755 sum = b[i]; 756 SPARSEDENSEMDOT(sum,xs,v,idx,n); 757 x[i] = (1. - omega)*x[i] + omega*(sum/d + x[i]); 758 } 759 } 760 if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){ 761 for ( i=m-1; i>=0; i-- ) { 762 d = fshift + a->a[diag[i] + shift]; 763 n = a->i[i+1] - a->i[i]; 764 idx = a->j + a->i[i] + shift; 765 v = a->a + a->i[i] + shift; 766 sum = b[i]; 767 SPARSEDENSEMDOT(sum,xs,v,idx,n); 768 x[i] = (1. - omega)*x[i] + omega*(sum/d + x[i]); 769 } 770 } 771 } 772 return 0; 773 } 774 775 static int MatGetInfo_SeqAIJ(Mat A,MatInfoType flag,int *nz,int *nzalloc,int *mem) 776 { 777 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 778 *nz = a->nz; 779 *nzalloc = a->maxnz; 780 *mem = (int)A->mem; 781 return 0; 782 } 783 784 extern int MatLUFactorSymbolic_SeqAIJ(Mat,IS,IS,double,Mat*); 785 extern int MatLUFactorNumeric_SeqAIJ(Mat,Mat*); 786 extern int MatLUFactor_SeqAIJ(Mat,IS,IS,double); 787 extern int MatSolve_SeqAIJ(Mat,Vec,Vec); 788 extern int MatSolveAdd_SeqAIJ(Mat,Vec,Vec,Vec); 789 extern int MatSolveTrans_SeqAIJ(Mat,Vec,Vec); 790 extern int MatSolveTransAdd_SeqAIJ(Mat,Vec,Vec,Vec); 791 792 static int MatZeroRows_SeqAIJ(Mat A,IS is,Scalar *diag) 793 { 794 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 795 int i,ierr,N, *rows,m = a->m - 1,shift = a->indexshift; 796 797 ierr = ISGetLocalSize(is,&N); CHKERRQ(ierr); 798 ierr = ISGetIndices(is,&rows); CHKERRQ(ierr); 799 if (diag) { 800 for ( i=0; i<N; i++ ) { 801 if (rows[i] < 0 || rows[i] > m) SETERRQ(1,"MatZeroRows_SeqAIJ:row out of range"); 802 if (a->ilen[rows[i]] > 0) { /* in case row was completely empty */ 803 a->ilen[rows[i]] = 1; 804 a->a[a->i[rows[i]]+shift] = *diag; 805 a->j[a->i[rows[i]]+shift] = rows[i]+shift; 806 } 807 else { 808 ierr = MatSetValues_SeqAIJ(A,1,&rows[i],1,&rows[i],diag,INSERT_VALUES); 809 CHKERRQ(ierr); 810 } 811 } 812 } 813 else { 814 for ( i=0; i<N; i++ ) { 815 if (rows[i] < 0 || rows[i] > m) SETERRQ(1,"MatZeroRows_SeqAIJ:row out of range"); 816 a->ilen[rows[i]] = 0; 817 } 818 } 819 ISRestoreIndices(is,&rows); 820 ierr = MatAssemblyBegin(A,FINAL_ASSEMBLY); CHKERRQ(ierr); 821 ierr = MatAssemblyEnd(A,FINAL_ASSEMBLY); CHKERRQ(ierr); 822 return 0; 823 } 824 825 static int MatGetSize_SeqAIJ(Mat A,int *m,int *n) 826 { 827 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 828 *m = a->m; *n = a->n; 829 return 0; 830 } 831 832 static int MatGetOwnershipRange_SeqAIJ(Mat A,int *m,int *n) 833 { 834 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 835 *m = 0; *n = a->m; 836 return 0; 837 } 838 static int MatGetRow_SeqAIJ(Mat A,int row,int *nz,int **idx,Scalar **v) 839 { 840 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 841 int *itmp,i,shift = a->indexshift; 842 843 if (row < 0 || row >= a->m) SETERRQ(1,"MatGetRow_SeqAIJ:Row out of range"); 844 845 *nz = a->i[row+1] - a->i[row]; 846 if (v) *v = a->a + a->i[row] + shift; 847 if (idx) { 848 if (*nz) { 849 itmp = a->j + a->i[row] + shift; 850 *idx = (int *) PetscMalloc( (*nz)*sizeof(int) ); CHKPTRQ(*idx); 851 for ( i=0; i<(*nz); i++ ) {(*idx)[i] = itmp[i] + shift;} 852 } 853 else *idx = 0; 854 } 855 return 0; 856 } 857 858 static int MatRestoreRow_SeqAIJ(Mat A,int row,int *nz,int **idx,Scalar **v) 859 { 860 if (idx) {if (*idx) PetscFree(*idx);} 861 return 0; 862 } 863 864 static int MatNorm_SeqAIJ(Mat A,NormType type,double *norm) 865 { 866 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 867 Scalar *v = a->a; 868 double sum = 0.0; 869 int i, j,shift = a->indexshift; 870 871 if (type == NORM_FROBENIUS) { 872 for (i=0; i<a->nz; i++ ) { 873 #if defined(PETSC_COMPLEX) 874 sum += real(conj(*v)*(*v)); v++; 875 #else 876 sum += (*v)*(*v); v++; 877 #endif 878 } 879 *norm = sqrt(sum); 880 } 881 else if (type == NORM_1) { 882 double *tmp; 883 int *jj = a->j; 884 tmp = (double *) PetscMalloc( a->n*sizeof(double) ); CHKPTRQ(tmp); 885 PetscMemzero(tmp,a->n*sizeof(double)); 886 *norm = 0.0; 887 for ( j=0; j<a->nz; j++ ) { 888 tmp[*jj++ + shift] += PetscAbsScalar(*v); v++; 889 } 890 for ( j=0; j<a->n; j++ ) { 891 if (tmp[j] > *norm) *norm = tmp[j]; 892 } 893 PetscFree(tmp); 894 } 895 else if (type == NORM_INFINITY) { 896 *norm = 0.0; 897 for ( j=0; j<a->m; j++ ) { 898 v = a->a + a->i[j] + shift; 899 sum = 0.0; 900 for ( i=0; i<a->i[j+1]-a->i[j]; i++ ) { 901 sum += PetscAbsScalar(*v); v++; 902 } 903 if (sum > *norm) *norm = sum; 904 } 905 } 906 else { 907 SETERRQ(1,"MatNorm_SeqAIJ:No support for two norm yet"); 908 } 909 return 0; 910 } 911 912 static int MatTranspose_SeqAIJ(Mat A,Mat *B) 913 { 914 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 915 Mat C; 916 int i, ierr, *aj = a->j, *ai = a->i, m = a->m, len, *col; 917 int shift = a->indexshift; 918 Scalar *array = a->a; 919 920 if (B == PETSC_NULL && m != a->n) 921 SETERRQ(1,"MatTranspose_MPIAIJ:Square matrix only for in-place"); 922 col = (int *) PetscMalloc((1+a->n)*sizeof(int)); CHKPTRQ(col); 923 PetscMemzero(col,(1+a->n)*sizeof(int)); 924 if (shift) { 925 for ( i=0; i<ai[m]-1; i++ ) aj[i] -= 1; 926 } 927 for ( i=0; i<ai[m]+shift; i++ ) col[aj[i]] += 1; 928 ierr = MatCreateSeqAIJ(A->comm,a->n,m,0,col,&C); CHKERRQ(ierr); 929 PetscFree(col); 930 for ( i=0; i<m; i++ ) { 931 len = ai[i+1]-ai[i]; 932 ierr = MatSetValues(C,len,aj,1,&i,array,INSERT_VALUES); CHKERRQ(ierr); 933 array += len; aj += len; 934 } 935 if (shift) { 936 for ( i=0; i<ai[m]-1; i++ ) aj[i] += 1; 937 } 938 939 ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 940 ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 941 942 if (B != PETSC_NULL) { 943 *B = C; 944 } else { 945 /* This isn't really an in-place transpose */ 946 PetscFree(a->a); 947 if (!a->singlemalloc) {PetscFree(a->i); PetscFree(a->j);} 948 if (a->diag) PetscFree(a->diag); 949 if (a->ilen) PetscFree(a->ilen); 950 if (a->imax) PetscFree(a->imax); 951 if (a->solve_work) PetscFree(a->solve_work); 952 PetscFree(a); 953 PetscMemcpy(A,C,sizeof(struct _Mat)); 954 PetscHeaderDestroy(C); 955 } 956 return 0; 957 } 958 959 static int MatDiagonalScale_SeqAIJ(Mat A,Vec ll,Vec rr) 960 { 961 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 962 Scalar *l,*r,x,*v; 963 int i,j,m = a->m, n = a->n, M, nz = a->nz, *jj,shift = a->indexshift; 964 965 if (ll) { 966 VecGetArray(ll,&l); VecGetSize(ll,&m); 967 if (m != a->m) SETERRQ(1,"MatDiagonalScale_SeqAIJ:Left scaling vector wrong length"); 968 v = a->a; 969 for ( i=0; i<m; i++ ) { 970 x = l[i]; 971 M = a->i[i+1] - a->i[i]; 972 for ( j=0; j<M; j++ ) { (*v++) *= x;} 973 } 974 } 975 if (rr) { 976 VecGetArray(rr,&r); VecGetSize(rr,&n); 977 if (n != a->n) SETERRQ(1,"MatDiagonalScale_SeqAIJ:Right scaling vector wrong length"); 978 v = a->a; jj = a->j; 979 for ( i=0; i<nz; i++ ) { 980 (*v++) *= r[*jj++ + shift]; 981 } 982 } 983 return 0; 984 } 985 986 static int MatGetSubMatrix_SeqAIJ(Mat A,IS isrow,IS iscol,MatGetSubMatrixCall scall,Mat *B) 987 { 988 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data,*c; 989 int nznew, *smap, i, k, kstart, kend, ierr, oldcols = a->n,*lens; 990 register int sum,lensi; 991 int *irow, *icol, nrows, ncols, *cwork, shift = a->indexshift,*ssmap; 992 int first,step,*starts,*j_new,*i_new,*aj = a->j, *ai = a->i,ii,*ailen = a->ilen; 993 Scalar *vwork,*a_new; 994 Mat C; 995 996 ierr = ISGetIndices(isrow,&irow); CHKERRQ(ierr); 997 ierr = ISGetSize(isrow,&nrows); CHKERRQ(ierr); 998 ierr = ISGetSize(iscol,&ncols); CHKERRQ(ierr); 999 1000 if (ISStrideGetInfo(iscol,&first,&step) && step == 1) { /* no need to sort */ 1001 /* special case of contiguous rows */ 1002 lens = (int *) PetscMalloc((2*ncols+1)*sizeof(int)); CHKPTRQ(lens); 1003 starts = lens + ncols; 1004 /* loop over new rows determining lens and starting points */ 1005 for (i=0; i<nrows; i++) { 1006 kstart = ai[irow[i]]+shift; 1007 kend = kstart + ailen[irow[i]]; 1008 for ( k=kstart; k<kend; k++ ) { 1009 if (aj[k]+shift >= first) { 1010 starts[i] = k; 1011 break; 1012 } 1013 } 1014 sum = 0; 1015 while (k < kend) { 1016 if (aj[k++]+shift >= first+ncols) break; 1017 sum++; 1018 } 1019 lens[i] = sum; 1020 } 1021 /* create submatrix */ 1022 if (scall == MAT_REUSE_MATRIX) { 1023 int n_cols,n_rows; 1024 ierr = MatGetSize(*B,&n_rows,&n_cols); CHKERRQ(ierr); 1025 if (n_rows != nrows || n_cols != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:"); 1026 ierr = MatZeroEntries(*B); CHKERRQ(ierr); 1027 C = *B; 1028 } 1029 else { 1030 ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr); 1031 } 1032 c = (Mat_SeqAIJ*) C->data; 1033 1034 /* loop over rows inserting into submatrix */ 1035 a_new = c->a; 1036 j_new = c->j; 1037 i_new = c->i; 1038 i_new[0] = -shift; 1039 for (i=0; i<nrows; i++) { 1040 ii = starts[i]; 1041 lensi = lens[i]; 1042 for ( k=0; k<lensi; k++ ) { 1043 *j_new++ = aj[ii+k] - first; 1044 } 1045 PetscMemcpy(a_new,a->a + starts[i],lensi*sizeof(Scalar)); 1046 a_new += lensi; 1047 i_new[i+1] = i_new[i] + lensi; 1048 c->ilen[i] = lensi; 1049 } 1050 PetscFree(lens); 1051 } 1052 else { 1053 ierr = ISGetIndices(iscol,&icol); CHKERRQ(ierr); 1054 ierr = SYIsort(ncols,icol); CHKERRQ(ierr); 1055 smap = (int *) PetscMalloc((1+oldcols)*sizeof(int)); CHKPTRQ(smap); 1056 ssmap = smap + shift; 1057 cwork = (int *) PetscMalloc((1+nrows+ncols)*sizeof(int)); CHKPTRQ(cwork); 1058 lens = cwork + ncols; 1059 vwork = (Scalar *) PetscMalloc((1+ncols)*sizeof(Scalar)); CHKPTRQ(vwork); 1060 PetscMemzero(smap,oldcols*sizeof(int)); 1061 for ( i=0; i<ncols; i++ ) smap[icol[i]] = i+1; 1062 /* determine lens of each row */ 1063 for (i=0; i<nrows; i++) { 1064 kstart = ai[irow[i]]+shift; 1065 kend = kstart + a->ilen[irow[i]]; 1066 lens[i] = 0; 1067 for ( k=kstart; k<kend; k++ ) { 1068 if (ssmap[aj[k]]) { 1069 lens[i]++; 1070 } 1071 } 1072 } 1073 /* Create and fill new matrix */ 1074 if (scall == MAT_REUSE_MATRIX) { 1075 int n_cols,n_rows; 1076 ierr = MatGetSize(*B,&n_rows,&n_cols); CHKERRQ(ierr); 1077 if (n_rows != nrows || n_cols != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:"); 1078 ierr = MatZeroEntries(*B); CHKERRQ(ierr); 1079 C = *B; 1080 } 1081 else { 1082 ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr); 1083 } 1084 for (i=0; i<nrows; i++) { 1085 nznew = 0; 1086 kstart = ai[irow[i]]+shift; 1087 kend = kstart + a->ilen[irow[i]]; 1088 for ( k=kstart; k<kend; k++ ) { 1089 if (ssmap[a->j[k]]) { 1090 cwork[nznew] = ssmap[a->j[k]] - 1; 1091 vwork[nznew++] = a->a[k]; 1092 } 1093 } 1094 ierr = MatSetValues(C,1,&i,nznew,cwork,vwork,INSERT_VALUES); CHKERRQ(ierr); 1095 } 1096 /* Free work space */ 1097 ierr = ISRestoreIndices(iscol,&icol); CHKERRQ(ierr); 1098 PetscFree(smap); PetscFree(cwork); PetscFree(vwork); 1099 } 1100 ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 1101 ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr); 1102 1103 ierr = ISRestoreIndices(isrow,&irow); CHKERRQ(ierr); 1104 *B = C; 1105 return 0; 1106 } 1107 1108 /* 1109 note: This can only work for identity for row and col. It would 1110 be good to check this and otherwise generate an error. 1111 */ 1112 static int MatILUFactor_SeqAIJ(Mat inA,IS row,IS col,double efill,int fill) 1113 { 1114 Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data; 1115 int ierr; 1116 Mat outA; 1117 1118 if (fill != 0) SETERRQ(1,"MatILUFactor_SeqAIJ:Only fill=0 supported"); 1119 1120 outA = inA; 1121 inA->factor = FACTOR_LU; 1122 a->row = row; 1123 a->col = col; 1124 1125 a->solve_work = (Scalar *) PetscMalloc( (a->m+1)*sizeof(Scalar)); CHKPTRQ(a->solve_work); 1126 1127 if (!a->diag) { 1128 ierr = MatMarkDiag_SeqAIJ(inA); CHKERRQ(ierr); 1129 } 1130 ierr = MatLUFactorNumeric_SeqAIJ(inA,&outA); CHKERRQ(ierr); 1131 return 0; 1132 } 1133 1134 #include "pinclude/plapack.h" 1135 static int MatScale_SeqAIJ(Scalar *alpha,Mat inA) 1136 { 1137 Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data; 1138 int one = 1; 1139 BLscal_( &a->nz, alpha, a->a, &one ); 1140 PLogFlops(a->nz); 1141 return 0; 1142 } 1143 1144 static int MatGetSubMatrices_SeqAIJ(Mat A,int n, IS *irow,IS *icol,MatGetSubMatrixCall scall, 1145 Mat **B) 1146 { 1147 int ierr,i; 1148 1149 if (scall == MAT_INITIAL_MATRIX) { 1150 *B = (Mat *) PetscMalloc( (n+1)*sizeof(Mat) ); CHKPTRQ(*B); 1151 } 1152 1153 for ( i=0; i<n; i++ ) { 1154 ierr = MatGetSubMatrix(A,irow[i],icol[i],scall,&(*B)[i]); CHKERRQ(ierr); 1155 } 1156 return 0; 1157 } 1158 1159 static int MatIncreaseOverlap_SeqAIJ(Mat A, int is_max, IS *is, int ov) 1160 { 1161 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 1162 int shift, row, i,j,k,l,m,n, *idx,ierr, *nidx, isz, val; 1163 int start, end, *ai, *aj; 1164 char *table; 1165 shift = a->indexshift; 1166 m = a->m; 1167 ai = a->i; 1168 aj = a->j+shift; 1169 1170 if (ov < 0) SETERRQ(1,"MatIncreaseOverlap_SeqAIJ: illegal overlap value used"); 1171 1172 table = (char *) PetscMalloc((m/BITSPERBYTE +1)*sizeof(char)); CHKPTRQ(table); 1173 nidx = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(nidx); 1174 1175 for ( i=0; i<is_max; i++ ) { 1176 /* Initialise the two local arrays */ 1177 isz = 0; 1178 PetscMemzero(table,(m/BITSPERBYTE +1)*sizeof(char)); 1179 1180 /* Extract the indices, assume there can be duplicate entries */ 1181 ierr = ISGetIndices(is[i],&idx); CHKERRQ(ierr); 1182 ierr = ISGetLocalSize(is[i],&n); CHKERRQ(ierr); 1183 1184 /* Enter these into the temp arrays i.e mark table[row], enter row into new index */ 1185 for ( j=0; j<n ; ++j){ 1186 if(!BT_LOOKUP(table, idx[j])) { nidx[isz++] = idx[j];} 1187 } 1188 ierr = ISRestoreIndices(is[i],&idx); CHKERRQ(ierr); 1189 ierr = ISDestroy(is[i]); CHKERRQ(ierr); 1190 1191 k = 0; 1192 for ( j=0; j<ov; j++){ /* for each overlap*/ 1193 n = isz; 1194 for ( ; k<n ; k++){ /* do only those rows in nidx[k], which are not done yet */ 1195 row = nidx[k]; 1196 start = ai[row]; 1197 end = ai[row+1]; 1198 for ( l = start; l<end ; l++){ 1199 val = aj[l] + shift; 1200 if (!BT_LOOKUP(table,val)) {nidx[isz++] = val;} 1201 } 1202 } 1203 } 1204 ierr = ISCreateSeq(MPI_COMM_SELF, isz, nidx, (is+i)); CHKERRQ(ierr); 1205 } 1206 PetscFree(table); 1207 PetscFree(nidx); 1208 return 0; 1209 } 1210 1211 int MatPrintHelp_SeqAIJ(Mat A) 1212 { 1213 static int called = 0; 1214 MPI_Comm comm = A->comm; 1215 1216 if (called) return 0; else called = 1; 1217 MPIU_printf(comm," Options for MATSEQAIJ and MATMPIAIJ matrix formats (the defaults):\n"); 1218 MPIU_printf(comm," -mat_lu_pivotthreshold <threshold>\n"); 1219 MPIU_printf(comm," -mat_aij_oneindex - internal indices begin at 1 instead of the default 0.\n"); 1220 MPIU_printf(comm," -mat_aij_no_inode - Do not use inodes\n"); 1221 MPIU_printf(comm," -mat_aij_inode_limit <limit> - Set inode limit (max limit=5)\n"); 1222 #if defined(HAVE_ESSL) 1223 MPIU_printf(comm," -mat_aij_essl - Use IBM sparse LU factorization and solve.\n"); 1224 #endif 1225 return 0; 1226 } 1227 int MatEqual_SeqAIJ(Mat A,Mat B, int* flg); 1228 /* -------------------------------------------------------------------*/ 1229 static struct _MatOps MatOps = {MatSetValues_SeqAIJ, 1230 MatGetRow_SeqAIJ,MatRestoreRow_SeqAIJ, 1231 MatMult_SeqAIJ,MatMultAdd_SeqAIJ, 1232 MatMultTrans_SeqAIJ,MatMultTransAdd_SeqAIJ, 1233 MatSolve_SeqAIJ,MatSolveAdd_SeqAIJ, 1234 MatSolveTrans_SeqAIJ,MatSolveTransAdd_SeqAIJ, 1235 MatLUFactor_SeqAIJ,0, 1236 MatRelax_SeqAIJ, 1237 MatTranspose_SeqAIJ, 1238 MatGetInfo_SeqAIJ,MatEqual_SeqAIJ, 1239 MatGetDiagonal_SeqAIJ,MatDiagonalScale_SeqAIJ,MatNorm_SeqAIJ, 1240 0,MatAssemblyEnd_SeqAIJ, 1241 MatCompress_SeqAIJ, 1242 MatSetOption_SeqAIJ,MatZeroEntries_SeqAIJ,MatZeroRows_SeqAIJ, 1243 MatGetReordering_SeqAIJ, 1244 MatLUFactorSymbolic_SeqAIJ,MatLUFactorNumeric_SeqAIJ,0,0, 1245 MatGetSize_SeqAIJ,MatGetSize_SeqAIJ,MatGetOwnershipRange_SeqAIJ, 1246 MatILUFactorSymbolic_SeqAIJ,0, 1247 0,0,MatConvert_SeqAIJ, 1248 MatGetSubMatrix_SeqAIJ,0, 1249 MatConvertSameType_SeqAIJ,0,0, 1250 MatILUFactor_SeqAIJ,0,0, 1251 MatGetSubMatrices_SeqAIJ,MatIncreaseOverlap_SeqAIJ, 1252 MatGetValues_SeqAIJ,0, 1253 MatPrintHelp_SeqAIJ, 1254 MatScale_SeqAIJ}; 1255 1256 extern int MatUseSuperLU_SeqAIJ(Mat); 1257 extern int MatUseEssl_SeqAIJ(Mat); 1258 extern int MatUseDXML_SeqAIJ(Mat); 1259 1260 /*@C 1261 MatCreateSeqAIJ - Creates a sparse matrix in AIJ (compressed row) format 1262 (the default parallel PETSc format). For good matrix assembly performance 1263 the user should preallocate the matrix storage by setting the parameter nz 1264 (or nzz). By setting these parameters accurately, performance can be 1265 increased by more than a factor of 50. 1266 1267 Input Parameters: 1268 . comm - MPI communicator, set to MPI_COMM_SELF 1269 . m - number of rows 1270 . n - number of columns 1271 . nz - number of nonzeros per row (same for all rows) 1272 . nzz - number of nonzeros per row or null (possibly different for each row) 1273 1274 Output Parameter: 1275 . A - the matrix 1276 1277 Notes: 1278 The AIJ format (also called the Yale sparse matrix format or 1279 compressed row storage), is fully compatible with standard Fortran 77 1280 storage. That is, the stored row and column indices can begin at 1281 either one (as in Fortran) or zero. See the users manual for details. 1282 1283 Specify the preallocated storage with either nz or nnz (not both). 1284 Set nz=PETSC_DEFAULT and nnz=PETSC_NULL for PETSc to control dynamic memory 1285 allocation. For additional details, see the users manual chapter on 1286 matrices and the file $(PETSC_DIR)/Performance. 1287 1288 By default, this format uses inodes (identical nodes) when possible, to 1289 improve numerical efficiency of Matrix vector products and solves. We 1290 search for consecutive rows with the same nonzero structure, thereby 1291 reusing matrix information to achieve increased efficiency. 1292 1293 Options Database Keys: 1294 $ -mat_aij_no_inode - Do not use inodes 1295 $ -mat_aij_inode_limit <limit> - Set inode limit. 1296 $ (max limit=5) 1297 $ -mat_aij_oneindex - Internally use indexing starting at 1 1298 $ rather than 0. Note: When calling MatSetValues(), 1299 $ the user still MUST index entries starting at 0! 1300 1301 .seealso: MatCreate(), MatCreateMPIAIJ(), MatSetValues() 1302 @*/ 1303 int MatCreateSeqAIJ(MPI_Comm comm,int m,int n,int nz,int *nnz, Mat *A) 1304 { 1305 Mat B; 1306 Mat_SeqAIJ *b; 1307 int i,len,ierr, flg; 1308 1309 *A = 0; 1310 PetscHeaderCreate(B,_Mat,MAT_COOKIE,MATSEQAIJ,comm); 1311 PLogObjectCreate(B); 1312 B->data = (void *) (b = PetscNew(Mat_SeqAIJ)); CHKPTRQ(b); 1313 PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps)); 1314 B->destroy = MatDestroy_SeqAIJ; 1315 B->view = MatView_SeqAIJ; 1316 B->factor = 0; 1317 B->lupivotthreshold = 1.0; 1318 ierr = OptionsGetDouble(PETSC_NULL,"-mat_lu_pivotthreshold",&B->lupivotthreshold, 1319 &flg); CHKERRQ(ierr); 1320 b->ilu_preserve_row_sums = PETSC_FALSE; 1321 ierr = OptionsHasName(PETSC_NULL,"-pc_ilu_preserve_row_sums", 1322 (int*) &b->ilu_preserve_row_sums); CHKERRQ(ierr); 1323 b->row = 0; 1324 b->col = 0; 1325 b->indexshift = 0; 1326 b->reallocs = 0; 1327 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_oneindex", &flg); CHKERRQ(ierr); 1328 if (flg) b->indexshift = -1; 1329 1330 b->m = m; 1331 b->n = n; 1332 b->imax = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(b->imax); 1333 if (nnz == PETSC_NULL) { 1334 if (nz == PETSC_DEFAULT) nz = 10; 1335 else if (nz <= 0) nz = 1; 1336 for ( i=0; i<m; i++ ) b->imax[i] = nz; 1337 nz = nz*m; 1338 } 1339 else { 1340 nz = 0; 1341 for ( i=0; i<m; i++ ) {b->imax[i] = nnz[i]; nz += nnz[i];} 1342 } 1343 1344 /* allocate the matrix space */ 1345 len = nz*(sizeof(int) + sizeof(Scalar)) + (b->m+1)*sizeof(int); 1346 b->a = (Scalar *) PetscMalloc( len ); CHKPTRQ(b->a); 1347 b->j = (int *) (b->a + nz); 1348 PetscMemzero(b->j,nz*sizeof(int)); 1349 b->i = b->j + nz; 1350 b->singlemalloc = 1; 1351 1352 b->i[0] = -b->indexshift; 1353 for (i=1; i<m+1; i++) { 1354 b->i[i] = b->i[i-1] + b->imax[i-1]; 1355 } 1356 1357 /* b->ilen will count nonzeros in each row so far. */ 1358 b->ilen = (int *) PetscMalloc((m+1)*sizeof(int)); 1359 PLogObjectMemory(B,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ)); 1360 for ( i=0; i<b->m; i++ ) { b->ilen[i] = 0;} 1361 1362 b->nz = 0; 1363 b->maxnz = nz; 1364 b->sorted = 0; 1365 b->roworiented = 1; 1366 b->nonew = 0; 1367 b->diag = 0; 1368 b->solve_work = 0; 1369 b->spptr = 0; 1370 b->inode.node_count = 0; 1371 b->inode.size = 0; 1372 b->inode.limit = 5; 1373 b->inode.max_limit = 5; 1374 1375 *A = B; 1376 /* SuperLU is not currently supported through PETSc */ 1377 #if defined(HAVE_SUPERLU) 1378 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_superlu", &flg); CHKERRQ(ierr); 1379 if (flg) { ierr = MatUseSuperLU_SeqAIJ(B); CHKERRQ(ierr); } 1380 #endif 1381 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_essl", &flg); CHKERRQ(ierr); 1382 if (flg) { ierr = MatUseEssl_SeqAIJ(B); CHKERRQ(ierr); } 1383 ierr = OptionsHasName(PETSC_NULL,"-mat_aij_dxml", &flg); CHKERRQ(ierr); 1384 if (flg) { 1385 if (!b->indexshift) SETERRQ(1,"MatCreateSeqAIJ:need -mat_aij_oneindex with -mat_aij_dxml"); 1386 ierr = MatUseDXML_SeqAIJ(B); CHKERRQ(ierr); 1387 } 1388 ierr = OptionsHasName(PETSC_NULL,"-help", &flg); CHKERRQ(ierr); 1389 if (flg) {ierr = MatPrintHelp(B); CHKERRQ(ierr); } 1390 return 0; 1391 } 1392 1393 int MatConvertSameType_SeqAIJ(Mat A,Mat *B,int cpvalues) 1394 { 1395 Mat C; 1396 Mat_SeqAIJ *c,*a = (Mat_SeqAIJ *) A->data; 1397 int i,len, m = a->m,shift = a->indexshift; 1398 1399 *B = 0; 1400 PetscHeaderCreate(C,_Mat,MAT_COOKIE,MATSEQAIJ,A->comm); 1401 PLogObjectCreate(C); 1402 C->data = (void *) (c = PetscNew(Mat_SeqAIJ)); CHKPTRQ(c); 1403 PetscMemcpy(&C->ops,&A->ops,sizeof(struct _MatOps)); 1404 C->destroy = MatDestroy_SeqAIJ; 1405 C->view = MatView_SeqAIJ; 1406 C->factor = A->factor; 1407 c->row = 0; 1408 c->col = 0; 1409 c->indexshift = shift; 1410 C->assembled = PETSC_TRUE; 1411 1412 c->m = a->m; 1413 c->n = a->n; 1414 1415 c->imax = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->imax); 1416 c->ilen = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->ilen); 1417 for ( i=0; i<m; i++ ) { 1418 c->imax[i] = a->imax[i]; 1419 c->ilen[i] = a->ilen[i]; 1420 } 1421 1422 /* allocate the matrix space */ 1423 c->singlemalloc = 1; 1424 len = (m+1)*sizeof(int)+(a->i[m])*(sizeof(Scalar)+sizeof(int)); 1425 c->a = (Scalar *) PetscMalloc( len ); CHKPTRQ(c->a); 1426 c->j = (int *) (c->a + a->i[m] + shift); 1427 c->i = c->j + a->i[m] + shift; 1428 PetscMemcpy(c->i,a->i,(m+1)*sizeof(int)); 1429 if (m > 0) { 1430 PetscMemcpy(c->j,a->j,(a->i[m]+shift)*sizeof(int)); 1431 if (cpvalues == COPY_VALUES) { 1432 PetscMemcpy(c->a,a->a,(a->i[m]+shift)*sizeof(Scalar)); 1433 } 1434 } 1435 1436 PLogObjectMemory(C,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ)); 1437 c->sorted = a->sorted; 1438 c->roworiented = a->roworiented; 1439 c->nonew = a->nonew; 1440 c->ilu_preserve_row_sums = a->ilu_preserve_row_sums; 1441 1442 if (a->diag) { 1443 c->diag = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(c->diag); 1444 PLogObjectMemory(C,(m+1)*sizeof(int)); 1445 for ( i=0; i<m; i++ ) { 1446 c->diag[i] = a->diag[i]; 1447 } 1448 } 1449 else c->diag = 0; 1450 c->inode.limit = a->inode.limit; 1451 c->inode.max_limit = a->inode.max_limit; 1452 if (a->inode.size){ 1453 c->inode.size = (int *) PetscMalloc( m *sizeof(int) ); CHKPTRQ(c->inode.size); 1454 c->inode.node_count = a->inode.node_count; 1455 PetscMemcpy( c->inode.size, a->inode.size, m*sizeof(int)); 1456 } else { 1457 c->inode.size = 0; 1458 c->inode.node_count = 0; 1459 } 1460 c->nz = a->nz; 1461 c->maxnz = a->maxnz; 1462 c->solve_work = 0; 1463 c->spptr = 0; /* Dangerous -I'm throwing away a->spptr */ 1464 1465 *B = C; 1466 return 0; 1467 } 1468 1469 int MatLoad_SeqAIJ(Viewer bview,MatType type,Mat *A) 1470 { 1471 Mat_SeqAIJ *a; 1472 Mat B; 1473 int i, nz, ierr, fd, header[4],size,*rowlengths = 0,M,N,shift; 1474 PetscObject vobj = (PetscObject) bview; 1475 MPI_Comm comm = vobj->comm; 1476 1477 MPI_Comm_size(comm,&size); 1478 if (size > 1) SETERRQ(1,"MatLoad_SeqAIJ:view must have one processor"); 1479 ierr = ViewerFileGetDescriptor_Private(bview,&fd); CHKERRQ(ierr); 1480 ierr = SYRead(fd,header,4,SYINT); CHKERRQ(ierr); 1481 if (header[0] != MAT_COOKIE) SETERRQ(1,"MatLoad_SeqAIJ:not matrix object in file"); 1482 M = header[1]; N = header[2]; nz = header[3]; 1483 1484 /* read in row lengths */ 1485 rowlengths = (int*) PetscMalloc( M*sizeof(int) ); CHKPTRQ(rowlengths); 1486 ierr = SYRead(fd,rowlengths,M,SYINT); CHKERRQ(ierr); 1487 1488 /* create our matrix */ 1489 ierr = MatCreateSeqAIJ(comm,M,N,0,rowlengths,A); CHKERRQ(ierr); 1490 B = *A; 1491 a = (Mat_SeqAIJ *) B->data; 1492 shift = a->indexshift; 1493 1494 /* read in column indices and adjust for Fortran indexing*/ 1495 ierr = SYRead(fd,a->j,nz,SYINT); CHKERRQ(ierr); 1496 if (shift) { 1497 for ( i=0; i<nz; i++ ) { 1498 a->j[i] += 1; 1499 } 1500 } 1501 1502 /* read in nonzero values */ 1503 ierr = SYRead(fd,a->a,nz,SYSCALAR); CHKERRQ(ierr); 1504 1505 /* set matrix "i" values */ 1506 a->i[0] = -shift; 1507 for ( i=1; i<= M; i++ ) { 1508 a->i[i] = a->i[i-1] + rowlengths[i-1]; 1509 a->ilen[i-1] = rowlengths[i-1]; 1510 } 1511 PetscFree(rowlengths); 1512 1513 ierr = MatAssemblyBegin(B,FINAL_ASSEMBLY); CHKERRQ(ierr); 1514 ierr = MatAssemblyEnd(B,FINAL_ASSEMBLY); CHKERRQ(ierr); 1515 return 0; 1516 } 1517 1518 1519 1520 /* 1521 1522 flg =0 if error; 1523 flg =1 if both are equal; 1524 */ 1525 int MatEqual_SeqAIJ(Mat A,Mat B, int* flg) 1526 { 1527 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data; 1528 1529 if (B->type !=MATSEQAIJ) SETERRQ(1,"MatEqual_SeqAIJ:Both matrices should be of type MATSEQAIJ"); 1530 1531 /* If the matrix dimensions are not equal, or no of nonzeros or shift */ 1532 if ((a->m != b->m ) || (a->n !=b->n) ||( a->nz != b->nz)|| 1533 (a->indexshift != b->indexshift)) { *flg =0 ; return 0; } 1534 1535 /* if the a->i are the same */ 1536 if(PetscMemcmp((char *)a->i, (char*)b->i, (a->n+1)*sizeof(int))) { *flg =0 ; return 0;} 1537 1538 /* if a->j are the same */ 1539 if(PetscMemcmp((char *)a->j, (char*)b->j, (a->nz)*sizeof(int))) { 1540 *flg =0 ; return 0; 1541 } 1542 1543 /* if a->j are the same */ 1544 if(PetscMemcmp((char *)a->a, (char*)b->a, (a->nz)*sizeof(Scalar))) { 1545 *flg =0 ; return 0; 1546 } 1547 *flg =1 ; 1548 return 0; 1549 1550 } 1551