Actual source code: mmaij.c


  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>

  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

 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:     }

 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:     }

 85:     /* make indices now point into garray */
 86:     for (i = 0; i < ec; i++) indices[garray[i]] = i;

 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:   }

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));

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));

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));

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;

120:   PetscCall(ISDestroy(&from));
121:   PetscCall(ISDestroy(&to));
122:   PetscCall(VecDestroy(&gvec));
123:   PetscFunctionReturn(PETSC_SUCCESS);
124: }

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;

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:   }

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));

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));

165:   if (Baij->nonew >= 0) { /* Inherit insertion error options (if positive). */
166:     ((Mat_SeqAIJ *)Bnew->data)->nonew = Baij->nonew;
167:   }

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;

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));

186:   PetscCall(PetscFree(aij->garray));
187:   PetscCall(MatDestroy(&B));

189:   aij->B           = Bnew;
190:   A->was_assembled = PETSC_FALSE;
191:   A->assembled     = PETSC_FALSE;
192:   PetscFunctionReturn(PETSC_SUCCESS);
193: }

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

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 */

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;

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));

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: }

247: PetscErrorCode MatMPIAIJDiagonalScaleLocal(Mat A, Vec scale)
248: {
249:   /* This routine should really be abandoned as it duplicates MatDiagonalScaleLocal */

251:   PetscFunctionBegin;
252:   PetscTryMethod(A, "MatDiagonalScaleLocal_C", (Mat, Vec), (A, scale));
253:   PetscFunctionReturn(PETSC_SUCCESS);
254: }

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;

263:   PetscFunctionBegin;
264:   if (!auglyrmapd) PetscCall(MatMPIAIJDiagonalScaleLocalSetUp(A, scale));

266:   PetscCall(VecGetArrayRead(scale, &s));

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));

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: }