xref: /petsc/src/mat/impls/aij/mpi/mmaij.c (revision 8ddb5d8b44839bc6385c771bd2d6d5c8cd353003)
1 
2 /*
3    Support for the parallel AIJ matrix vector multiply
4 */
5 #include <../src/mat/impls/aij/mpi/mpiaij.h>
6 
7 #undef __FUNCT__
8 #define __FUNCT__ "MatSetUpMultiply_MPIAIJ"
9 PetscErrorCode MatSetUpMultiply_MPIAIJ(Mat mat)
10 {
11   Mat_MPIAIJ         *aij = (Mat_MPIAIJ*)mat->data;
12   Mat_SeqAIJ         *B = (Mat_SeqAIJ*)(aij->B->data);
13   PetscErrorCode     ierr;
14   PetscInt           i,j,*aj = B->j,ec = 0,*garray;
15   IS                 from,to;
16   Vec                gvec;
17   PetscBool          useblockis;
18 #if defined (PETSC_USE_CTABLE)
19   PetscTable         gid1_lid1;
20   PetscTablePosition tpos;
21   PetscInt           gid,lid;
22 #else
23   PetscInt           N = mat->cmap->N,*indices;
24 #endif
25 
26   PetscFunctionBegin;
27 
28 #if defined (PETSC_USE_CTABLE)
29   /* use a table - Mark Adams */
30   ierr = PetscTableCreate(aij->B->rmap->n,mat->cmap->N+1,&gid1_lid1);CHKERRQ(ierr);
31   for (i=0; i<aij->B->rmap->n; i++) {
32     for (j=0; j<B->ilen[i]; j++) {
33       PetscInt data,gid1 = aj[B->i[i] + j] + 1;
34       ierr = PetscTableFind(gid1_lid1,gid1,&data);CHKERRQ(ierr);
35       if (!data) {
36         /* one based table */
37         ierr = PetscTableAdd(gid1_lid1,gid1,++ec,INSERT_VALUES);CHKERRQ(ierr);
38       }
39     }
40   }
41   /* form array of columns we need */
42   ierr = PetscMalloc((ec+1)*sizeof(PetscInt),&garray);CHKERRQ(ierr);
43   ierr = PetscTableGetHeadPosition(gid1_lid1,&tpos);CHKERRQ(ierr);
44   while (tpos) {
45     ierr = PetscTableGetNext(gid1_lid1,&tpos,&gid,&lid);CHKERRQ(ierr);
46     gid--;
47     lid--;
48     garray[lid] = gid;
49   }
50   ierr = PetscSortInt(ec,garray);CHKERRQ(ierr); /* sort, and rebuild */
51   ierr = PetscTableRemoveAll(gid1_lid1);CHKERRQ(ierr);
52   for (i=0; i<ec; i++) {
53     ierr = PetscTableAdd(gid1_lid1,garray[i]+1,i+1,INSERT_VALUES);CHKERRQ(ierr);
54   }
55   /* compact out the extra columns in B */
56   for (i=0; i<aij->B->rmap->n; i++) {
57     for (j=0; j<B->ilen[i]; j++) {
58       PetscInt gid1 = aj[B->i[i] + j] + 1;
59       ierr = PetscTableFind(gid1_lid1,gid1,&lid);CHKERRQ(ierr);
60       lid --;
61       aj[B->i[i] + j]  = lid;
62     }
63   }
64   aij->B->cmap->n = aij->B->cmap->N = ec;
65   ierr = PetscLayoutSetUp((aij->B->cmap));CHKERRQ(ierr);
66   ierr = PetscTableDestroy(&gid1_lid1);CHKERRQ(ierr);
67   /* Mark Adams */
68 #else
69   /* Make an array as long as the number of columns */
70   /* mark those columns that are in aij->B */
71   ierr = PetscMalloc((N+1)*sizeof(PetscInt),&indices);CHKERRQ(ierr);
72   ierr = PetscMemzero(indices,N*sizeof(PetscInt));CHKERRQ(ierr);
73   for (i=0; i<aij->B->rmap->n; i++) {
74     for (j=0; j<B->ilen[i]; j++) {
75       if (!indices[aj[B->i[i] + j] ]) ec++;
76       indices[aj[B->i[i] + j] ] = 1;
77     }
78   }
79 
80   /* form array of columns we need */
81   ierr = PetscMalloc((ec+1)*sizeof(PetscInt),&garray);CHKERRQ(ierr);
82   ec = 0;
83   for (i=0; i<N; i++) {
84     if (indices[i]) garray[ec++] = i;
85   }
86 
87   /* make indices now point into garray */
88   for (i=0; i<ec; i++) {
89     indices[garray[i]] = i;
90   }
91 
92   /* compact out the extra columns in B */
93   for (i=0; i<aij->B->rmap->n; i++) {
94     for (j=0; j<B->ilen[i]; j++) {
95       aj[B->i[i] + j] = indices[aj[B->i[i] + j]];
96     }
97   }
98   aij->B->cmap->n = aij->B->cmap->N = ec;
99   ierr = PetscLayoutSetUp((aij->B->cmap));CHKERRQ(ierr);
100   ierr = PetscFree(indices);CHKERRQ(ierr);
101 #endif
102   /* create local vector that is used to scatter into */
103   ierr = VecCreateSeq(PETSC_COMM_SELF,ec,&aij->lvec);CHKERRQ(ierr);
104 
105   /* create two temporary Index sets for build scatter gather */
106   /*  check for the special case where blocks are communicated for faster VecScatterXXX */
107   useblockis = PETSC_TRUE;
108   if (mat->rmap->bs > 1) {
109     PetscInt bs = mat->rmap->bs,ibs,ga;
110     if (!(ec % bs)) {
111       for (i=0; i<ec/bs; i++) {
112         if ((ga = garray[ibs = i*bs]) % bs) {
113           useblockis = PETSC_FALSE;
114           break;
115         }
116         for (j=1; j<bs; j++) {
117           if (garray[ibs+j] != ga+j) {
118             useblockis = PETSC_FALSE;
119             break;
120           }
121         }
122         if (!useblockis) break;
123       }
124     }
125   }
126   if (useblockis) {
127     PetscInt *ga,bs = mat->rmap->bs,iec = ec/bs;
128     ierr = PetscInfo(mat,"Using block index set to define scatter\n");
129     ierr = PetscMalloc((ec/mat->rmap->bs)*sizeof(PetscInt),&ga);CHKERRQ(ierr);
130     for (i=0; i<iec; i++) ga[i] = garray[i*bs]/bs;
131     ierr = ISCreateBlock(((PetscObject)mat)->comm,bs,iec,ga,PETSC_OWN_POINTER,&from);CHKERRQ(ierr);
132   } else {
133     ierr = ISCreateGeneral(((PetscObject)mat)->comm,ec,garray,PETSC_COPY_VALUES,&from);CHKERRQ(ierr);
134   }
135   ierr = ISCreateStride(PETSC_COMM_SELF,ec,0,1,&to);CHKERRQ(ierr);
136 
137   /* create temporary global vector to generate scatter context */
138   /* This does not allocate the array's memory so is efficient */
139   ierr = VecCreateMPIWithArray(((PetscObject)mat)->comm,mat->cmap->n,mat->cmap->N,PETSC_NULL,&gvec);CHKERRQ(ierr);
140 
141   /* generate the scatter context */
142   ierr = VecScatterCreate(gvec,from,aij->lvec,to,&aij->Mvctx);CHKERRQ(ierr);
143   ierr = PetscLogObjectParent(mat,aij->Mvctx);CHKERRQ(ierr);
144   ierr = PetscLogObjectParent(mat,aij->lvec);CHKERRQ(ierr);
145   ierr = PetscLogObjectParent(mat,from);CHKERRQ(ierr);
146   ierr = PetscLogObjectParent(mat,to);CHKERRQ(ierr);
147   aij->garray = garray;
148   ierr = PetscLogObjectMemory(mat,(ec+1)*sizeof(PetscInt));CHKERRQ(ierr);
149   ierr = ISDestroy(&from);CHKERRQ(ierr);
150   ierr = ISDestroy(&to);CHKERRQ(ierr);
151   ierr = VecDestroy(&gvec);CHKERRQ(ierr);
152   PetscFunctionReturn(0);
153 }
154 
155 
156 #undef __FUNCT__
157 #define __FUNCT__ "DisAssemble_MPIAIJ"
158 /*
159      Takes the local part of an already assembled MPIAIJ matrix
160    and disassembles it. This is to allow new nonzeros into the matrix
161    that require more communication in the matrix vector multiply.
162    Thus certain data-structures must be rebuilt.
163 
164    Kind of slow! But that's what application programmers get when
165    they are sloppy.
166 */
167 PetscErrorCode DisAssemble_MPIAIJ(Mat A)
168 {
169   Mat_MPIAIJ     *aij = (Mat_MPIAIJ*)A->data;
170   Mat            B = aij->B,Bnew;
171   Mat_SeqAIJ     *Baij = (Mat_SeqAIJ*)B->data;
172   PetscErrorCode ierr;
173   PetscInt       i,j,m = B->rmap->n,n = A->cmap->N,col,ct = 0,*garray = aij->garray,*nz,ec;
174   PetscScalar    v;
175 
176   PetscFunctionBegin;
177   /* free stuff related to matrix-vec multiply */
178   ierr = VecGetSize(aij->lvec,&ec);CHKERRQ(ierr); /* needed for PetscLogObjectMemory below */
179   ierr = VecDestroy(&aij->lvec);CHKERRQ(ierr); aij->lvec = 0;
180   ierr = VecScatterDestroy(&aij->Mvctx);CHKERRQ(ierr); aij->Mvctx = 0;
181   if (aij->colmap) {
182 #if defined (PETSC_USE_CTABLE)
183     ierr = PetscTableDestroy(&aij->colmap);CHKERRQ(ierr);
184 #else
185     ierr = PetscFree(aij->colmap);CHKERRQ(ierr);
186     ierr = PetscLogObjectMemory(A,-aij->B->cmap->n*sizeof(PetscInt));CHKERRQ(ierr);
187 #endif
188   }
189 
190   /* make sure that B is assembled so we can access its values */
191   ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
192   ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
193 
194   /* invent new B and copy stuff over */
195   ierr = PetscMalloc((m+1)*sizeof(PetscInt),&nz);CHKERRQ(ierr);
196   for (i=0; i<m; i++) {
197     nz[i] = Baij->i[i+1] - Baij->i[i];
198   }
199   ierr = MatCreate(PETSC_COMM_SELF,&Bnew);CHKERRQ(ierr);
200   ierr = MatSetSizes(Bnew,m,n,m,n);CHKERRQ(ierr);
201   ierr = MatSetType(Bnew,((PetscObject)B)->type_name);CHKERRQ(ierr);
202   ierr = MatSeqAIJSetPreallocation(Bnew,0,nz);CHKERRQ(ierr);
203   ((Mat_SeqAIJ*)Bnew->data)->nonew = Baij->nonew; /* Inherit insertion error options. */
204   ierr = PetscFree(nz);CHKERRQ(ierr);
205   for (i=0; i<m; i++) {
206     for (j=Baij->i[i]; j<Baij->i[i+1]; j++) {
207       col  = garray[Baij->j[ct]];
208       v    = Baij->a[ct++];
209       ierr = MatSetValues(Bnew,1,&i,1,&col,&v,B->insertmode);CHKERRQ(ierr);
210     }
211   }
212   ierr = PetscFree(aij->garray);CHKERRQ(ierr);
213   ierr = PetscLogObjectMemory(A,-ec*sizeof(PetscInt));CHKERRQ(ierr);
214   ierr = MatDestroy(&B);CHKERRQ(ierr);
215   ierr = PetscLogObjectParent(A,Bnew);CHKERRQ(ierr);
216   aij->B = Bnew;
217   A->was_assembled = PETSC_FALSE;
218   PetscFunctionReturn(0);
219 }
220 
221 /*      ugly stuff added for Glenn someday we should fix this up */
222 
223 static PetscInt *auglyrmapd = 0,*auglyrmapo = 0;  /* mapping from the local ordering to the "diagonal" and "off-diagonal"
224                                       parts of the local matrix */
225 static Vec auglydd = 0,auglyoo = 0;   /* work vectors used to scale the two parts of the local matrix */
226 
227 
228 #undef __FUNCT__
229 #define __FUNCT__ "MatMPIAIJDiagonalScaleLocalSetUp"
230 PetscErrorCode MatMPIAIJDiagonalScaleLocalSetUp(Mat inA,Vec scale)
231 {
232   Mat_MPIAIJ     *ina = (Mat_MPIAIJ*) inA->data; /*access private part of matrix */
233   PetscErrorCode ierr;
234   PetscInt       i,n,nt,cstart,cend,no,*garray = ina->garray,*lindices;
235   PetscInt       *r_rmapd,*r_rmapo;
236 
237   PetscFunctionBegin;
238   ierr = MatGetOwnershipRange(inA,&cstart,&cend);CHKERRQ(ierr);
239   ierr = MatGetSize(ina->A,PETSC_NULL,&n);CHKERRQ(ierr);
240   ierr = PetscMalloc((inA->rmap->mapping->n+1)*sizeof(PetscInt),&r_rmapd);CHKERRQ(ierr);
241   ierr = PetscMemzero(r_rmapd,inA->rmap->mapping->n*sizeof(PetscInt));CHKERRQ(ierr);
242   nt   = 0;
243   for (i=0; i<inA->rmap->mapping->n; i++) {
244     if (inA->rmap->mapping->indices[i] >= cstart && inA->rmap->mapping->indices[i] < cend) {
245       nt++;
246       r_rmapd[i] = inA->rmap->mapping->indices[i] + 1;
247     }
248   }
249   if (nt != n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Hmm nt %D n %D",nt,n);
250   ierr = PetscMalloc((n+1)*sizeof(PetscInt),&auglyrmapd);CHKERRQ(ierr);
251   for (i=0; i<inA->rmap->mapping->n; i++) {
252     if (r_rmapd[i]){
253       auglyrmapd[(r_rmapd[i]-1)-cstart] = i;
254     }
255   }
256   ierr = PetscFree(r_rmapd);CHKERRQ(ierr);
257   ierr = VecCreateSeq(PETSC_COMM_SELF,n,&auglydd);CHKERRQ(ierr);
258 
259   ierr = PetscMalloc((inA->cmap->N+1)*sizeof(PetscInt),&lindices);CHKERRQ(ierr);
260   ierr = PetscMemzero(lindices,inA->cmap->N*sizeof(PetscInt));CHKERRQ(ierr);
261   for (i=0; i<ina->B->cmap->n; i++) {
262     lindices[garray[i]] = i+1;
263   }
264   no   = inA->rmap->mapping->n - nt;
265   ierr = PetscMalloc((inA->rmap->mapping->n+1)*sizeof(PetscInt),&r_rmapo);CHKERRQ(ierr);
266   ierr = PetscMemzero(r_rmapo,inA->rmap->mapping->n*sizeof(PetscInt));CHKERRQ(ierr);
267   nt   = 0;
268   for (i=0; i<inA->rmap->mapping->n; i++) {
269     if (lindices[inA->rmap->mapping->indices[i]]) {
270       nt++;
271       r_rmapo[i] = lindices[inA->rmap->mapping->indices[i]];
272     }
273   }
274   if (nt > no) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Hmm nt %D no %D",nt,n);
275   ierr = PetscFree(lindices);CHKERRQ(ierr);
276   ierr = PetscMalloc((nt+1)*sizeof(PetscInt),&auglyrmapo);CHKERRQ(ierr);
277   for (i=0; i<inA->rmap->mapping->n; i++) {
278     if (r_rmapo[i]){
279       auglyrmapo[(r_rmapo[i]-1)] = i;
280     }
281   }
282   ierr = PetscFree(r_rmapo);CHKERRQ(ierr);
283   ierr = VecCreateSeq(PETSC_COMM_SELF,nt,&auglyoo);CHKERRQ(ierr);
284 
285   PetscFunctionReturn(0);
286 }
287 
288 #undef __FUNCT__
289 #define __FUNCT__ "MatMPIAIJDiagonalScaleLocal"
290 PetscErrorCode MatMPIAIJDiagonalScaleLocal(Mat A,Vec scale)
291 {
292   /* This routine should really be abandoned as it duplicates MatDiagonalScaleLocal */
293   PetscErrorCode ierr;
294 
295   PetscFunctionBegin;
296   ierr = PetscTryMethod(A,"MatDiagonalScaleLocal_C",(Mat,Vec),(A,scale));CHKERRQ(ierr);
297   PetscFunctionReturn(0);
298 }
299 
300 EXTERN_C_BEGIN
301 #undef __FUNCT__
302 #define __FUNCT__ "MatDiagonalScaleLocal_MPIAIJ"
303 PetscErrorCode  MatDiagonalScaleLocal_MPIAIJ(Mat A,Vec scale)
304 {
305   Mat_MPIAIJ     *a = (Mat_MPIAIJ*) A->data; /*access private part of matrix */
306   PetscErrorCode ierr;
307   PetscInt       n,i;
308   PetscScalar    *d,*o,*s;
309 
310   PetscFunctionBegin;
311   if (!auglyrmapd) {
312     ierr = MatMPIAIJDiagonalScaleLocalSetUp(A,scale);CHKERRQ(ierr);
313   }
314 
315   ierr = VecGetArray(scale,&s);CHKERRQ(ierr);
316 
317   ierr = VecGetLocalSize(auglydd,&n);CHKERRQ(ierr);
318   ierr = VecGetArray(auglydd,&d);CHKERRQ(ierr);
319   for (i=0; i<n; i++) {
320     d[i] = s[auglyrmapd[i]]; /* copy "diagonal" (true local) portion of scale into dd vector */
321   }
322   ierr = VecRestoreArray(auglydd,&d);CHKERRQ(ierr);
323   /* column scale "diagonal" portion of local matrix */
324   ierr = MatDiagonalScale(a->A,PETSC_NULL,auglydd);CHKERRQ(ierr);
325 
326   ierr = VecGetLocalSize(auglyoo,&n);CHKERRQ(ierr);
327   ierr = VecGetArray(auglyoo,&o);CHKERRQ(ierr);
328   for (i=0; i<n; i++) {
329     o[i] = s[auglyrmapo[i]]; /* copy "off-diagonal" portion of scale into oo vector */
330   }
331   ierr = VecRestoreArray(scale,&s);CHKERRQ(ierr);
332   ierr = VecRestoreArray(auglyoo,&o);CHKERRQ(ierr);
333   /* column scale "off-diagonal" portion of local matrix */
334   ierr = MatDiagonalScale(a->B,PETSC_NULL,auglyoo);CHKERRQ(ierr);
335 
336   PetscFunctionReturn(0);
337 }
338 EXTERN_C_END
339 
340 
341