Actual source code: mmaij.c

  1: #define PETSCMAT_DLL

  3: /*
  4:    Support for the parallel AIJ matrix vector multiply
  5: */
 6:  #include ../src/mat/impls/aij/mpi/mpiaij.h

 10: PetscErrorCode MatSetUpMultiply_MPIAIJ(Mat mat)
 11: {
 12:   Mat_MPIAIJ         *aij = (Mat_MPIAIJ*)mat->data;
 13:   Mat_SeqAIJ         *B = (Mat_SeqAIJ*)(aij->B->data);
 14:   PetscErrorCode     ierr;
 15:   PetscInt           i,j,*aj = B->j,ec = 0,*garray;
 16:   IS                 from,to;
 17:   Vec                gvec;
 18:   PetscTruth         useblockis;
 19: #if defined (PETSC_USE_CTABLE)
 20:   PetscTable         gid1_lid1;
 21:   PetscTablePosition tpos;
 22:   PetscInt           gid,lid;
 23: #else
 24:   PetscInt           N = mat->cmap->N,*indices;
 25: #endif


 29: #if defined (PETSC_USE_CTABLE)
 30:   /* use a table - Mark Adams */
 31:   PetscTableCreate(aij->B->rmap->n,&gid1_lid1);
 32:   for (i=0; i<aij->B->rmap->n; i++) {
 33:     for (j=0; j<B->ilen[i]; j++) {
 34:       PetscInt data,gid1 = aj[B->i[i] + j] + 1;
 35:       PetscTableFind(gid1_lid1,gid1,&data);
 36:       if (!data) {
 37:         /* one based table */
 38:         PetscTableAdd(gid1_lid1,gid1,++ec);
 39:       }
 40:     }
 41:   }
 42:   /* form array of columns we need */
 43:   PetscMalloc((ec+1)*sizeof(PetscInt),&garray);
 44:   PetscTableGetHeadPosition(gid1_lid1,&tpos);
 45:   while (tpos) {
 46:     PetscTableGetNext(gid1_lid1,&tpos,&gid,&lid);
 47:     gid--;
 48:     lid--;
 49:     garray[lid] = gid;
 50:   }
 51:   PetscSortInt(ec,garray); /* sort, and rebuild */
 52:   PetscTableRemoveAll(gid1_lid1);
 53:   for (i=0; i<ec; i++) {
 54:     PetscTableAdd(gid1_lid1,garray[i]+1,i+1);
 55:   }
 56:   /* compact out the extra columns in B */
 57:   for (i=0; i<aij->B->rmap->n; i++) {
 58:     for (j=0; j<B->ilen[i]; j++) {
 59:       PetscInt gid1 = aj[B->i[i] + j] + 1;
 60:       PetscTableFind(gid1_lid1,gid1,&lid);
 61:       lid --;
 62:       aj[B->i[i] + j]  = lid;
 63:     }
 64:   }
 65:   aij->B->cmap->n = aij->B->cmap->N = ec;
 66:   PetscLayoutSetUp((aij->B->cmap));
 67:   PetscTableDestroy(gid1_lid1);
 68:   /* Mark Adams */
 69: #else
 70:   /* Make an array as long as the number of columns */
 71:   /* mark those columns that are in aij->B */
 72:   PetscMalloc((N+1)*sizeof(PetscInt),&indices);
 73:   PetscMemzero(indices,N*sizeof(PetscInt));
 74:   for (i=0; i<aij->B->rmap->n; i++) {
 75:     for (j=0; j<B->ilen[i]; j++) {
 76:       if (!indices[aj[B->i[i] + j] ]) ec++;
 77:       indices[aj[B->i[i] + j] ] = 1;
 78:     }
 79:   }

 81:   /* form array of columns we need */
 82:   PetscMalloc((ec+1)*sizeof(PetscInt),&garray);
 83:   ec = 0;
 84:   for (i=0; i<N; i++) {
 85:     if (indices[i]) garray[ec++] = i;
 86:   }

 88:   /* make indices now point into garray */
 89:   for (i=0; i<ec; i++) {
 90:     indices[garray[i]] = i;
 91:   }

 93:   /* compact out the extra columns in B */
 94:   for (i=0; i<aij->B->rmap->n; i++) {
 95:     for (j=0; j<B->ilen[i]; j++) {
 96:       aj[B->i[i] + j] = indices[aj[B->i[i] + j]];
 97:     }
 98:   }
 99:   aij->B->cmap->n = aij->B->cmap->N = ec;
100:   PetscLayoutSetUp((aij->B->cmap));
101:   PetscFree(indices);
102: #endif  
103:   /* create local vector that is used to scatter into */
104:   VecCreateSeq(PETSC_COMM_SELF,ec,&aij->lvec);

106:   /* create two temporary Index sets for build scatter gather */
107:   /*  check for the special case where blocks are communicated for faster VecScatterXXX */
108:   useblockis = PETSC_TRUE;
109:   if (mat->rmap->bs > 1) {
110:     PetscInt bs = mat->rmap->bs,ibs,ga;
111:     if (!(ec % bs)) {
112:       for (i=0; i<ec/bs; i++) {
113:         if ((ga = garray[ibs = i*bs]) % bs) {
114:           useblockis = PETSC_FALSE;
115:           break;
116:         }
117:         for (j=1; j<bs; j++) {
118:           if (garray[ibs+j] != ga+j) {
119:             useblockis = PETSC_FALSE;
120:             break;
121:           }
122:         }
123:         if (!useblockis) break;
124:       }
125:     }
126:   }
127:   if (useblockis) {
128:     PetscInt *ga,bs = mat->rmap->bs,iec = ec/bs;
129:     PetscInfo(mat,"Using block index set to define scatter\n");
130:     PetscMalloc((ec/mat->rmap->bs)*sizeof(PetscInt),&ga);
131:     for (i=0; i<iec; i++) ga[i] = garray[i*bs];
132:     ISCreateBlock(((PetscObject)mat)->comm,bs,iec,ga,&from);
133:     PetscFree(ga);
134:   } else {
135:     ISCreateGeneral(((PetscObject)mat)->comm,ec,garray,&from);
136:   }
137:   ISCreateStride(PETSC_COMM_SELF,ec,0,1,&to);

139:   /* create temporary global vector to generate scatter context */
140:   /* This does not allocate the array's memory so is efficient */
141:   VecCreateMPIWithArray(((PetscObject)mat)->comm,mat->cmap->n,mat->cmap->N,PETSC_NULL,&gvec);

143:   /* generate the scatter context */
144:   VecScatterCreate(gvec,from,aij->lvec,to,&aij->Mvctx);
145:   PetscLogObjectParent(mat,aij->Mvctx);
146:   PetscLogObjectParent(mat,aij->lvec);
147:   PetscLogObjectParent(mat,from);
148:   PetscLogObjectParent(mat,to);
149:   aij->garray = garray;
150:   PetscLogObjectMemory(mat,(ec+1)*sizeof(PetscInt));
151:   ISDestroy(from);
152:   ISDestroy(to);
153:   VecDestroy(gvec);
154:   return(0);
155: }


160: /*
161:      Takes the local part of an already assembled MPIAIJ matrix
162:    and disassembles it. This is to allow new nonzeros into the matrix
163:    that require more communication in the matrix vector multiply. 
164:    Thus certain data-structures must be rebuilt.

166:    Kind of slow! But that's what application programmers get when 
167:    they are sloppy.
168: */
169: PetscErrorCode DisAssemble_MPIAIJ(Mat A)
170: {
171:   Mat_MPIAIJ     *aij = (Mat_MPIAIJ*)A->data;
172:   Mat            B = aij->B,Bnew;
173:   Mat_SeqAIJ     *Baij = (Mat_SeqAIJ*)B->data;
175:   PetscInt       i,j,m = B->rmap->n,n = A->cmap->N,col,ct = 0,*garray = aij->garray,*nz,ec;
176:   PetscScalar    v;

179:   /* free stuff related to matrix-vec multiply */
180:   VecGetSize(aij->lvec,&ec); /* needed for PetscLogObjectMemory below */
181:   VecDestroy(aij->lvec); aij->lvec = 0;
182:   VecScatterDestroy(aij->Mvctx); aij->Mvctx = 0;
183:   if (aij->colmap) {
184: #if defined (PETSC_USE_CTABLE)
185:     PetscTableDestroy(aij->colmap);
186:     aij->colmap = 0;
187: #else
188:     PetscFree(aij->colmap);
189:     aij->colmap = 0;
190:     PetscLogObjectMemory(A,-aij->B->cmap->n*sizeof(PetscInt));
191: #endif
192:   }

194:   /* make sure that B is assembled so we can access its values */
195:   MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
196:   MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);

198:   /* invent new B and copy stuff over */
199:   PetscMalloc((m+1)*sizeof(PetscInt),&nz);
200:   for (i=0; i<m; i++) {
201:     nz[i] = Baij->i[i+1] - Baij->i[i];
202:   }
203:   MatCreate(PETSC_COMM_SELF,&Bnew);
204:   MatSetSizes(Bnew,m,n,m,n);
205:   MatSetType(Bnew,((PetscObject)B)->type_name);
206:   MatSeqAIJSetPreallocation(Bnew,0,nz);
207:   PetscFree(nz);
208:   for (i=0; i<m; i++) {
209:     for (j=Baij->i[i]; j<Baij->i[i+1]; j++) {
210:       col  = garray[Baij->j[ct]];
211:       v    = Baij->a[ct++];
212:       MatSetValues(Bnew,1,&i,1,&col,&v,B->insertmode);
213:     }
214:   }
215:   PetscFree(aij->garray);
216:   aij->garray = 0;
217:   PetscLogObjectMemory(A,-ec*sizeof(PetscInt));
218:   MatDestroy(B);
219:   PetscLogObjectParent(A,Bnew);
220:   aij->B = Bnew;
221:   A->was_assembled = PETSC_FALSE;
222:   return(0);
223: }

225: /*      ugly stuff added for Glenn someday we should fix this up */

227: static PetscInt *auglyrmapd = 0,*auglyrmapo = 0;  /* mapping from the local ordering to the "diagonal" and "off-diagonal"
228:                                       parts of the local matrix */
229: static Vec auglydd = 0,auglyoo = 0;   /* work vectors used to scale the two parts of the local matrix */


234: PetscErrorCode MatMPIAIJDiagonalScaleLocalSetUp(Mat inA,Vec scale)
235: {
236:   Mat_MPIAIJ     *ina = (Mat_MPIAIJ*) inA->data; /*access private part of matrix */
238:   PetscInt       i,n,nt,cstart,cend,no,*garray = ina->garray,*lindices;
239:   PetscInt       *r_rmapd,*r_rmapo;
240: 
242:   MatGetOwnershipRange(inA,&cstart,&cend);
243:   MatGetSize(ina->A,PETSC_NULL,&n);
244:   PetscMalloc((inA->mapping->n+1)*sizeof(PetscInt),&r_rmapd);
245:   PetscMemzero(r_rmapd,inA->mapping->n*sizeof(PetscInt));
246:   nt   = 0;
247:   for (i=0; i<inA->mapping->n; i++) {
248:     if (inA->mapping->indices[i] >= cstart && inA->mapping->indices[i] < cend) {
249:       nt++;
250:       r_rmapd[i] = inA->mapping->indices[i] + 1;
251:     }
252:   }
253:   if (nt != n) SETERRQ2(PETSC_ERR_PLIB,"Hmm nt %D n %D",nt,n);
254:   PetscMalloc((n+1)*sizeof(PetscInt),&auglyrmapd);
255:   for (i=0; i<inA->mapping->n; i++) {
256:     if (r_rmapd[i]){
257:       auglyrmapd[(r_rmapd[i]-1)-cstart] = i;
258:     }
259:   }
260:   PetscFree(r_rmapd);
261:   VecCreateSeq(PETSC_COMM_SELF,n,&auglydd);

263:   PetscMalloc((inA->cmap->N+1)*sizeof(PetscInt),&lindices);
264:   PetscMemzero(lindices,inA->cmap->N*sizeof(PetscInt));
265:   for (i=0; i<ina->B->cmap->n; i++) {
266:     lindices[garray[i]] = i+1;
267:   }
268:   no   = inA->mapping->n - nt;
269:   PetscMalloc((inA->mapping->n+1)*sizeof(PetscInt),&r_rmapo);
270:   PetscMemzero(r_rmapo,inA->mapping->n*sizeof(PetscInt));
271:   nt   = 0;
272:   for (i=0; i<inA->mapping->n; i++) {
273:     if (lindices[inA->mapping->indices[i]]) {
274:       nt++;
275:       r_rmapo[i] = lindices[inA->mapping->indices[i]];
276:     }
277:   }
278:   if (nt > no) SETERRQ2(PETSC_ERR_PLIB,"Hmm nt %D no %D",nt,n);
279:   PetscFree(lindices);
280:   PetscMalloc((nt+1)*sizeof(PetscInt),&auglyrmapo);
281:   for (i=0; i<inA->mapping->n; i++) {
282:     if (r_rmapo[i]){
283:       auglyrmapo[(r_rmapo[i]-1)] = i;
284:     }
285:   }
286:   PetscFree(r_rmapo);
287:   VecCreateSeq(PETSC_COMM_SELF,nt,&auglyoo);

289:   return(0);
290: }

294: PetscErrorCode MatMPIAIJDiagonalScaleLocal(Mat A,Vec scale)
295: {
296:   /* This routine should really be abandoned as it duplicates MatDiagonalScaleLocal */
297:   PetscErrorCode ierr,(*f)(Mat,Vec);

300:   PetscObjectQueryFunction((PetscObject)A,"MatDiagonalScaleLocal_C",(void (**)(void))&f);
301:   if (f) {
302:     (*f)(A,scale);
303:   }
304:   return(0);
305: }

310: PetscErrorCode  MatDiagonalScaleLocal_MPIAIJ(Mat A,Vec scale)
311: {
312:   Mat_MPIAIJ     *a = (Mat_MPIAIJ*) A->data; /*access private part of matrix */
314:   PetscInt       n,i;
315:   PetscScalar    *d,*o,*s;
316: 
318:   if (!auglyrmapd) {
319:     MatMPIAIJDiagonalScaleLocalSetUp(A,scale);
320:   }

322:   VecGetArray(scale,&s);
323: 
324:   VecGetLocalSize(auglydd,&n);
325:   VecGetArray(auglydd,&d);
326:   for (i=0; i<n; i++) {
327:     d[i] = s[auglyrmapd[i]]; /* copy "diagonal" (true local) portion of scale into dd vector */
328:   }
329:   VecRestoreArray(auglydd,&d);
330:   /* column scale "diagonal" portion of local matrix */
331:   MatDiagonalScale(a->A,PETSC_NULL,auglydd);

333:   VecGetLocalSize(auglyoo,&n);
334:   VecGetArray(auglyoo,&o);
335:   for (i=0; i<n; i++) {
336:     o[i] = s[auglyrmapo[i]]; /* copy "off-diagonal" portion of scale into oo vector */
337:   }
338:   VecRestoreArray(scale,&s);
339:   VecRestoreArray(auglyoo,&o);
340:   /* column scale "off-diagonal" portion of local matrix */
341:   MatDiagonalScale(a->B,PETSC_NULL,auglyoo);

343:   return(0);
344: }