xref: /petsc/src/mat/impls/aij/mpi/mmaij.c (revision df4cd43f92eaa320656440c40edb1046daee8f75)
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(PETSC_SUCCESS);
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   A->assembled     = PETSC_FALSE;
192   PetscFunctionReturn(PETSC_SUCCESS);
193 }
194 
195 /*      ugly stuff added for Glenn someday we should fix this up */
196 
197 static PetscInt *auglyrmapd = NULL, *auglyrmapo = NULL; /* mapping from the local ordering to the "diagonal" and "off-diagonal" parts of the local matrix */
198 static Vec       auglydd = NULL, auglyoo = NULL;        /* work vectors used to scale the two parts of the local matrix */
199 
200 PetscErrorCode MatMPIAIJDiagonalScaleLocalSetUp(Mat inA, Vec scale)
201 {
202   Mat_MPIAIJ *ina = (Mat_MPIAIJ *)inA->data; /*access private part of matrix */
203   PetscInt    i, n, nt, cstart, cend, no, *garray = ina->garray, *lindices;
204   PetscInt   *r_rmapd, *r_rmapo;
205 
206   PetscFunctionBegin;
207   PetscCall(MatGetOwnershipRange(inA, &cstart, &cend));
208   PetscCall(MatGetSize(ina->A, NULL, &n));
209   PetscCall(PetscCalloc1(inA->rmap->mapping->n + 1, &r_rmapd));
210   nt = 0;
211   for (i = 0; i < inA->rmap->mapping->n; i++) {
212     if (inA->rmap->mapping->indices[i] >= cstart && inA->rmap->mapping->indices[i] < cend) {
213       nt++;
214       r_rmapd[i] = inA->rmap->mapping->indices[i] + 1;
215     }
216   }
217   PetscCheck(nt == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hmm nt %" PetscInt_FMT " n %" PetscInt_FMT, nt, n);
218   PetscCall(PetscMalloc1(n + 1, &auglyrmapd));
219   for (i = 0; i < inA->rmap->mapping->n; i++) {
220     if (r_rmapd[i]) auglyrmapd[(r_rmapd[i] - 1) - cstart] = i;
221   }
222   PetscCall(PetscFree(r_rmapd));
223   PetscCall(VecCreateSeq(PETSC_COMM_SELF, n, &auglydd));
224 
225   PetscCall(PetscCalloc1(inA->cmap->N + 1, &lindices));
226   for (i = 0; i < ina->B->cmap->n; i++) lindices[garray[i]] = i + 1;
227   no = inA->rmap->mapping->n - nt;
228   PetscCall(PetscCalloc1(inA->rmap->mapping->n + 1, &r_rmapo));
229   nt = 0;
230   for (i = 0; i < inA->rmap->mapping->n; i++) {
231     if (lindices[inA->rmap->mapping->indices[i]]) {
232       nt++;
233       r_rmapo[i] = lindices[inA->rmap->mapping->indices[i]];
234     }
235   }
236   PetscCheck(nt <= no, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hmm nt %" PetscInt_FMT " no %" PetscInt_FMT, nt, n);
237   PetscCall(PetscFree(lindices));
238   PetscCall(PetscMalloc1(nt + 1, &auglyrmapo));
239   for (i = 0; i < inA->rmap->mapping->n; i++) {
240     if (r_rmapo[i]) auglyrmapo[(r_rmapo[i] - 1)] = i;
241   }
242   PetscCall(PetscFree(r_rmapo));
243   PetscCall(VecCreateSeq(PETSC_COMM_SELF, nt, &auglyoo));
244   PetscFunctionReturn(PETSC_SUCCESS);
245 }
246 
247 PetscErrorCode MatMPIAIJDiagonalScaleLocal(Mat A, Vec scale)
248 {
249   /* This routine should really be abandoned as it duplicates MatDiagonalScaleLocal */
250 
251   PetscFunctionBegin;
252   PetscTryMethod(A, "MatDiagonalScaleLocal_C", (Mat, Vec), (A, scale));
253   PetscFunctionReturn(PETSC_SUCCESS);
254 }
255 
256 PetscErrorCode MatDiagonalScaleLocal_MPIAIJ(Mat A, Vec scale)
257 {
258   Mat_MPIAIJ        *a = (Mat_MPIAIJ *)A->data; /*access private part of matrix */
259   PetscInt           n, i;
260   PetscScalar       *d, *o;
261   const PetscScalar *s;
262 
263   PetscFunctionBegin;
264   if (!auglyrmapd) PetscCall(MatMPIAIJDiagonalScaleLocalSetUp(A, scale));
265 
266   PetscCall(VecGetArrayRead(scale, &s));
267 
268   PetscCall(VecGetLocalSize(auglydd, &n));
269   PetscCall(VecGetArray(auglydd, &d));
270   for (i = 0; i < n; i++) { d[i] = s[auglyrmapd[i]]; /* copy "diagonal" (true local) portion of scale into dd vector */ }
271   PetscCall(VecRestoreArray(auglydd, &d));
272   /* column scale "diagonal" portion of local matrix */
273   PetscCall(MatDiagonalScale(a->A, NULL, auglydd));
274 
275   PetscCall(VecGetLocalSize(auglyoo, &n));
276   PetscCall(VecGetArray(auglyoo, &o));
277   for (i = 0; i < n; i++) { o[i] = s[auglyrmapo[i]]; /* copy "off-diagonal" portion of scale into oo vector */ }
278   PetscCall(VecRestoreArrayRead(scale, &s));
279   PetscCall(VecRestoreArray(auglyoo, &o));
280   /* column scale "off-diagonal" portion of local matrix */
281   PetscCall(MatDiagonalScale(a->B, NULL, auglyoo));
282   PetscFunctionReturn(PETSC_SUCCESS);
283 }
284