xref: /petsc/src/mat/impls/aij/mpi/mmaij.c (revision e874ec00d637a86419bb2cc912cf88b33e5547ef)
1 
2 /*
3    Support for the parallel AIJ matrix vector multiply
4 */
5 #include <../src/mat/impls/aij/mpi/mpiaij.h>
6 #include <petsc/private/vecimpl.h>
7 #include <petsc/private/isimpl.h> /* needed because accesses data structure of ISLocalToGlobalMapping directly */
8 
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   PetscInt    i, j, *aj = B->j, *garray;
14   PetscInt    ec = 0; /* Number of nonzero external columns */
15   IS          from, to;
16   Vec         gvec;
17 #if defined(PETSC_USE_CTABLE)
18   PetscHMapI    gid1_lid1 = NULL;
19   PetscHashIter tpos;
20   PetscInt      gid, lid;
21 #else
22   PetscInt N = mat->cmap->N, *indices;
23 #endif
24 
25   PetscFunctionBegin;
26   if (!aij->garray) {
27     PetscCheck(aij->B, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing B mat");
28 #if defined(PETSC_USE_CTABLE)
29     /* use a table */
30     PetscCall(PetscHMapICreateWithSize(aij->B->rmap->n, &gid1_lid1));
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         PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &data));
35         if (!data) {
36           /* one based table */
37           PetscCall(PetscHMapISet(gid1_lid1, gid1, ++ec));
38         }
39       }
40     }
41     /* form array of columns we need */
42     PetscCall(PetscMalloc1(ec, &garray));
43     PetscHashIterBegin(gid1_lid1, tpos);
44     while (!PetscHashIterAtEnd(gid1_lid1, tpos)) {
45       PetscHashIterGetKey(gid1_lid1, tpos, gid);
46       PetscHashIterGetVal(gid1_lid1, tpos, lid);
47       PetscHashIterNext(gid1_lid1, tpos);
48       gid--;
49       lid--;
50       garray[lid] = gid;
51     }
52     PetscCall(PetscSortInt(ec, garray)); /* sort, and rebuild */
53     PetscCall(PetscHMapIClear(gid1_lid1));
54     for (i = 0; i < ec; i++) PetscCall(PetscHMapISet(gid1_lid1, garray[i] + 1, i + 1));
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         PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &lid));
60         lid--;
61         aj[B->i[i] + j] = lid;
62       }
63     }
64     PetscCall(PetscLayoutDestroy(&aij->B->cmap));
65     PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)aij->B), ec, ec, 1, &aij->B->cmap));
66     PetscCall(PetscHMapIDestroy(&gid1_lid1));
67 #else
68     /* Make an array as long as the number of columns */
69     /* mark those columns that are in aij->B */
70     PetscCall(PetscCalloc1(N, &indices));
71     for (i = 0; i < aij->B->rmap->n; i++) {
72       for (j = 0; j < B->ilen[i]; j++) {
73         if (!indices[aj[B->i[i] + j]]) ec++;
74         indices[aj[B->i[i] + j]] = 1;
75       }
76     }
77 
78     /* form array of columns we need */
79     PetscCall(PetscMalloc1(ec, &garray));
80     ec = 0;
81     for (i = 0; i < N; i++) {
82       if (indices[i]) garray[ec++] = i;
83     }
84 
85     /* make indices now point into garray */
86     for (i = 0; i < ec; i++) indices[garray[i]] = i;
87 
88     /* compact out the extra columns in B */
89     for (i = 0; i < aij->B->rmap->n; i++) {
90       for (j = 0; j < B->ilen[i]; j++) aj[B->i[i] + j] = indices[aj[B->i[i] + j]];
91     }
92     PetscCall(PetscLayoutDestroy(&aij->B->cmap));
93     PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)aij->B), ec, ec, 1, &aij->B->cmap));
94     PetscCall(PetscFree(indices));
95 #endif
96   } else {
97     garray = aij->garray;
98   }
99 
100   if (!aij->lvec) {
101     PetscCheck(aij->B, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing B mat");
102     PetscCall(MatCreateVecs(aij->B, &aij->lvec, NULL));
103   }
104   PetscCall(VecGetSize(aij->lvec, &ec));
105 
106   /* create two temporary Index sets for build scatter gather */
107   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ec, garray, PETSC_COPY_VALUES, &from));
108   PetscCall(ISCreateStride(PETSC_COMM_SELF, ec, 0, 1, &to));
109 
110   /* create temporary global vector to generate scatter context */
111   /* This does not allocate the array's memory so is efficient */
112   PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)mat), 1, mat->cmap->n, mat->cmap->N, NULL, &gvec));
113 
114   /* generate the scatter context */
115   PetscCall(VecScatterDestroy(&aij->Mvctx));
116   PetscCall(VecScatterCreate(gvec, from, aij->lvec, to, &aij->Mvctx));
117   PetscCall(VecScatterViewFromOptions(aij->Mvctx, (PetscObject)mat, "-matmult_vecscatter_view"));
118   aij->garray = garray;
119 
120   PetscCall(ISDestroy(&from));
121   PetscCall(ISDestroy(&to));
122   PetscCall(VecDestroy(&gvec));
123   PetscFunctionReturn(0);
124 }
125 
126 /* Disassemble the off-diag portion of the MPIAIJXxx matrix.
127    In other words, change the B from reduced format using local col ids
128    to expanded format using global col ids, which will make it easier to
129    insert new nonzeros (with global col ids) into the matrix.
130    The off-diag B determines communication in the matrix vector multiply.
131 */
132 PetscErrorCode MatDisAssemble_MPIAIJ(Mat A)
133 {
134   Mat_MPIAIJ        *aij  = (Mat_MPIAIJ *)A->data;
135   Mat                B    = aij->B, Bnew;
136   Mat_SeqAIJ        *Baij = (Mat_SeqAIJ *)B->data;
137   PetscInt           i, j, m = B->rmap->n, n = A->cmap->N, col, ct = 0, *garray = aij->garray, *nz;
138   PetscScalar        v;
139   const PetscScalar *ba;
140 
141   PetscFunctionBegin;
142   /* free stuff related to matrix-vec multiply */
143   PetscCall(VecDestroy(&aij->lvec));
144   if (aij->colmap) {
145 #if defined(PETSC_USE_CTABLE)
146     PetscCall(PetscHMapIDestroy(&aij->colmap));
147 #else
148     PetscCall(PetscFree(aij->colmap));
149 #endif
150   }
151 
152   /* make sure that B is assembled so we can access its values */
153   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
154   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
155 
156   /* invent new B and copy stuff over */
157   PetscCall(PetscMalloc1(m + 1, &nz));
158   for (i = 0; i < m; i++) nz[i] = Baij->i[i + 1] - Baij->i[i];
159   PetscCall(MatCreate(PETSC_COMM_SELF, &Bnew));
160   PetscCall(MatSetSizes(Bnew, m, n, m, n)); /* Bnew now uses A->cmap->N as its col size */
161   PetscCall(MatSetBlockSizesFromMats(Bnew, A, A));
162   PetscCall(MatSetType(Bnew, ((PetscObject)B)->type_name));
163   PetscCall(MatSeqAIJSetPreallocation(Bnew, 0, nz));
164 
165   if (Baij->nonew >= 0) { /* Inherit insertion error options (if positive). */
166     ((Mat_SeqAIJ *)Bnew->data)->nonew = Baij->nonew;
167   }
168 
169   /*
170    Ensure that B's nonzerostate is monotonically increasing.
171    Or should this follow the MatSetValues() loop to preserve B's nonzerstate across a MatDisAssemble() call?
172    */
173   Bnew->nonzerostate = B->nonzerostate;
174 
175   PetscCall(PetscFree(nz));
176   PetscCall(MatSeqAIJGetArrayRead(B, &ba));
177   for (i = 0; i < m; i++) {
178     for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) {
179       col = garray[Baij->j[ct]];
180       v   = ba[ct++];
181       PetscCall(MatSetValues(Bnew, 1, &i, 1, &col, &v, B->insertmode));
182     }
183   }
184   PetscCall(MatSeqAIJRestoreArrayRead(B, &ba));
185 
186   PetscCall(PetscFree(aij->garray));
187   PetscCall(MatDestroy(&B));
188 
189   aij->B           = Bnew;
190   A->was_assembled = PETSC_FALSE;
191   PetscFunctionReturn(0);
192 }
193 
194 /*      ugly stuff added for Glenn someday we should fix this up */
195 
196 static PetscInt *auglyrmapd = NULL, *auglyrmapo = NULL; /* mapping from the local ordering to the "diagonal" and "off-diagonal" parts of the local matrix */
197 static Vec       auglydd = NULL, auglyoo = NULL;        /* work vectors used to scale the two parts of the local matrix */
198 
199 PetscErrorCode MatMPIAIJDiagonalScaleLocalSetUp(Mat inA, Vec scale)
200 {
201   Mat_MPIAIJ *ina = (Mat_MPIAIJ *)inA->data; /*access private part of matrix */
202   PetscInt    i, n, nt, cstart, cend, no, *garray = ina->garray, *lindices;
203   PetscInt   *r_rmapd, *r_rmapo;
204 
205   PetscFunctionBegin;
206   PetscCall(MatGetOwnershipRange(inA, &cstart, &cend));
207   PetscCall(MatGetSize(ina->A, NULL, &n));
208   PetscCall(PetscCalloc1(inA->rmap->mapping->n + 1, &r_rmapd));
209   nt = 0;
210   for (i = 0; i < inA->rmap->mapping->n; i++) {
211     if (inA->rmap->mapping->indices[i] >= cstart && inA->rmap->mapping->indices[i] < cend) {
212       nt++;
213       r_rmapd[i] = inA->rmap->mapping->indices[i] + 1;
214     }
215   }
216   PetscCheck(nt == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hmm nt %" PetscInt_FMT " n %" PetscInt_FMT, nt, n);
217   PetscCall(PetscMalloc1(n + 1, &auglyrmapd));
218   for (i = 0; i < inA->rmap->mapping->n; i++) {
219     if (r_rmapd[i]) auglyrmapd[(r_rmapd[i] - 1) - cstart] = i;
220   }
221   PetscCall(PetscFree(r_rmapd));
222   PetscCall(VecCreateSeq(PETSC_COMM_SELF, n, &auglydd));
223 
224   PetscCall(PetscCalloc1(inA->cmap->N + 1, &lindices));
225   for (i = 0; i < ina->B->cmap->n; i++) lindices[garray[i]] = i + 1;
226   no = inA->rmap->mapping->n - nt;
227   PetscCall(PetscCalloc1(inA->rmap->mapping->n + 1, &r_rmapo));
228   nt = 0;
229   for (i = 0; i < inA->rmap->mapping->n; i++) {
230     if (lindices[inA->rmap->mapping->indices[i]]) {
231       nt++;
232       r_rmapo[i] = lindices[inA->rmap->mapping->indices[i]];
233     }
234   }
235   PetscCheck(nt <= no, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hmm nt %" PetscInt_FMT " no %" PetscInt_FMT, nt, n);
236   PetscCall(PetscFree(lindices));
237   PetscCall(PetscMalloc1(nt + 1, &auglyrmapo));
238   for (i = 0; i < inA->rmap->mapping->n; i++) {
239     if (r_rmapo[i]) auglyrmapo[(r_rmapo[i] - 1)] = i;
240   }
241   PetscCall(PetscFree(r_rmapo));
242   PetscCall(VecCreateSeq(PETSC_COMM_SELF, nt, &auglyoo));
243   PetscFunctionReturn(0);
244 }
245 
246 PetscErrorCode MatMPIAIJDiagonalScaleLocal(Mat A, Vec scale)
247 {
248   /* This routine should really be abandoned as it duplicates MatDiagonalScaleLocal */
249 
250   PetscFunctionBegin;
251   PetscTryMethod(A, "MatDiagonalScaleLocal_C", (Mat, Vec), (A, scale));
252   PetscFunctionReturn(0);
253 }
254 
255 PetscErrorCode MatDiagonalScaleLocal_MPIAIJ(Mat A, Vec scale)
256 {
257   Mat_MPIAIJ        *a = (Mat_MPIAIJ *)A->data; /*access private part of matrix */
258   PetscInt           n, i;
259   PetscScalar       *d, *o;
260   const PetscScalar *s;
261 
262   PetscFunctionBegin;
263   if (!auglyrmapd) PetscCall(MatMPIAIJDiagonalScaleLocalSetUp(A, scale));
264 
265   PetscCall(VecGetArrayRead(scale, &s));
266 
267   PetscCall(VecGetLocalSize(auglydd, &n));
268   PetscCall(VecGetArray(auglydd, &d));
269   for (i = 0; i < n; i++) { d[i] = s[auglyrmapd[i]]; /* copy "diagonal" (true local) portion of scale into dd vector */ }
270   PetscCall(VecRestoreArray(auglydd, &d));
271   /* column scale "diagonal" portion of local matrix */
272   PetscCall(MatDiagonalScale(a->A, NULL, auglydd));
273 
274   PetscCall(VecGetLocalSize(auglyoo, &n));
275   PetscCall(VecGetArray(auglyoo, &o));
276   for (i = 0; i < n; i++) { o[i] = s[auglyrmapo[i]]; /* copy "off-diagonal" portion of scale into oo vector */ }
277   PetscCall(VecRestoreArrayRead(scale, &s));
278   PetscCall(VecRestoreArray(auglyoo, &o));
279   /* column scale "off-diagonal" portion of local matrix */
280   PetscCall(MatDiagonalScale(a->B, NULL, auglyoo));
281   PetscFunctionReturn(0);
282 }
283