Actual source code: pdvec.c

  1: /*
  2:      Code for some of the parallel vector primitives.
  3: */
  4: #include <../src/vec/vec/impls/mpi/pvecimpl.h>
  5: #include <petsc/private/viewerhdf5impl.h>
  6: #include <petsc/private/glvisviewerimpl.h>
  7: #include <petsc/private/glvisvecimpl.h>
  8: #include <petscsf.h>

 10: static PetscErrorCode VecResetPreallocationCOO_MPI(Vec v)
 11: {
 12:   Vec_MPI *vmpi = (Vec_MPI *)v->data;

 14:   PetscFunctionBegin;
 15:   if (vmpi) {
 16:     PetscCall(PetscFree(vmpi->jmap1));
 17:     PetscCall(PetscFree(vmpi->perm1));
 18:     PetscCall(PetscFree(vmpi->Cperm));
 19:     PetscCall(PetscFree4(vmpi->imap2, vmpi->jmap2, vmpi->sendbuf, vmpi->recvbuf));
 20:     PetscCall(PetscFree(vmpi->perm2));
 21:     PetscCall(PetscSFDestroy(&vmpi->coo_sf));
 22:   }
 23:   PetscFunctionReturn(PETSC_SUCCESS);
 24: }

 26: PetscErrorCode VecDestroy_MPI(Vec v)
 27: {
 28:   Vec_MPI *x = (Vec_MPI *)v->data;

 30:   PetscFunctionBegin;
 31:   PetscCall(PetscLogObjectState((PetscObject)v, "Length=%" PetscInt_FMT, v->map->N));
 32:   if (!x) PetscFunctionReturn(PETSC_SUCCESS);
 33:   PetscCall(PetscFree(x->array_allocated));

 35:   /* Destroy local representation of vector if it exists */
 36:   if (x->localrep) {
 37:     PetscCall(VecDestroy(&x->localrep));
 38:     PetscCall(VecScatterDestroy(&x->localupdate));
 39:     PetscCall(ISDestroy(&x->ghost));
 40:   }
 41:   PetscCall(VecAssemblyReset_MPI(v));

 43:   /* Destroy the stashes: note the order - so that the tags are freed properly */
 44:   PetscCall(VecStashDestroy_Private(&v->bstash));
 45:   PetscCall(VecStashDestroy_Private(&v->stash));

 47:   PetscCall(VecResetPreallocationCOO_MPI(v));
 48:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscMatlabEnginePut_C", NULL));
 49:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscMatlabEngineGet_C", NULL));
 50:   PetscCall(PetscFree(v->data));
 51:   PetscFunctionReturn(PETSC_SUCCESS);
 52: }

 54: static PetscErrorCode VecView_MPI_ASCII(Vec xin, PetscViewer viewer)
 55: {
 56:   PetscInt           i, work = xin->map->n, cnt, nLen;
 57:   PetscMPIInt        j, n = 0, size, rank, tag = ((PetscObject)viewer)->tag, len;
 58:   MPI_Status         status;
 59:   PetscScalar       *values;
 60:   const PetscScalar *xarray;
 61:   const char        *name;
 62:   PetscViewerFormat  format;

 64:   PetscFunctionBegin;
 65:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)xin), &size));
 66:   PetscCall(PetscViewerGetFormat(viewer, &format));
 67:   if (format == PETSC_VIEWER_LOAD_BALANCE) {
 68:     PetscInt nmax = 0, nmin = xin->map->n, navg;
 69:     for (PetscMPIInt i = 0; i < size; i++) {
 70:       nmax = PetscMax(nmax, xin->map->range[i + 1] - xin->map->range[i]);
 71:       nmin = PetscMin(nmin, xin->map->range[i + 1] - xin->map->range[i]);
 72:     }
 73:     navg = xin->map->N / size;
 74:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Load Balance - Local vector size Min %" PetscInt_FMT "  avg %" PetscInt_FMT "  max %" PetscInt_FMT "\n", nmin, navg, nmax));
 75:     PetscFunctionReturn(PETSC_SUCCESS);
 76:   }

 78:   PetscCall(VecGetArrayRead(xin, &xarray));
 79:   /* determine maximum message to arrive */
 80:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)xin), &rank));
 81:   PetscCallMPI(MPI_Reduce(rank ? &work : MPI_IN_PLACE, &work, 1, MPIU_INT, MPI_MAX, 0, PetscObjectComm((PetscObject)xin)));
 82:   PetscCall(PetscMPIIntCast(work, &len));
 83:   if (format == PETSC_VIEWER_ASCII_GLVIS) rank = 0, len = 0; /* no parallel distributed write support from GLVis */
 84:   if (rank == 0) {
 85:     PetscCall(PetscMalloc1(len, &values));
 86:     /*
 87:         MATLAB format and ASCII format are very similar except
 88:         MATLAB uses %18.16e format while ASCII uses %g
 89:     */
 90:     if (format == PETSC_VIEWER_ASCII_MATLAB) {
 91:       PetscCall(PetscObjectGetName((PetscObject)xin, &name));
 92:       PetscCall(PetscViewerASCIIPrintf(viewer, "%s = [\n", name));
 93:       for (i = 0; i < xin->map->n; i++) {
 94:         if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(xarray[i]) > 0.0) {
 95:           PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e + %18.16ei\n", (double)PetscRealPart(xarray[i]), (double)PetscImaginaryPart(xarray[i])));
 96:         } else if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(xarray[i]) < 0.0) {
 97:           PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e - %18.16ei\n", (double)PetscRealPart(xarray[i]), -(double)PetscImaginaryPart(xarray[i])));
 98:         } else {
 99:           PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e\n", (double)PetscRealPart(xarray[i])));
100:         }
101:       }
102:       /* receive and print messages */
103:       for (j = 1; j < size; j++) {
104:         PetscCallMPI(MPI_Recv(values, len, MPIU_SCALAR, j, tag, PetscObjectComm((PetscObject)xin), &status));
105:         PetscCallMPI(MPI_Get_count(&status, MPIU_SCALAR, &n));
106:         for (i = 0; i < n; i++) {
107:           if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(values[i]) > 0.0) {
108:             PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e + %18.16ei\n", (double)PetscRealPart(values[i]), (double)PetscImaginaryPart(values[i])));
109:           } else if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(values[i]) < 0.0) {
110:             PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e - %18.16ei\n", (double)PetscRealPart(values[i]), -(double)PetscImaginaryPart(values[i])));
111:           } else {
112:             PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e\n", (double)PetscRealPart(values[i])));
113:           }
114:         }
115:       }
116:       PetscCall(PetscViewerASCIIPrintf(viewer, "];\n"));

118:     } else if (format == PETSC_VIEWER_ASCII_SYMMODU) {
119:       for (i = 0; i < xin->map->n; i++) {
120: #if PetscDefined(USE_COMPLEX)
121:         PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e %18.16e\n", (double)PetscRealPart(xarray[i]), (double)PetscImaginaryPart(xarray[i])));
122: #else
123:         PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e\n", (double)xarray[i]));
124: #endif
125:       }
126:       /* receive and print messages */
127:       for (j = 1; j < size; j++) {
128:         PetscCallMPI(MPI_Recv(values, len, MPIU_SCALAR, j, tag, PetscObjectComm((PetscObject)xin), &status));
129:         PetscCallMPI(MPI_Get_count(&status, MPIU_SCALAR, &n));
130:         for (i = 0; i < n; i++) {
131: #if PetscDefined(USE_COMPLEX)
132:           PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e %18.16e\n", (double)PetscRealPart(values[i]), (double)PetscImaginaryPart(values[i])));
133: #else
134:           PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e\n", (double)values[i]));
135: #endif
136:         }
137:       }
138:     } else if (format == PETSC_VIEWER_ASCII_PCICE) {
139:       PetscInt bs, b, vertexCount = 1;

141:       PetscCall(VecGetLocalSize(xin, &nLen));
142:       PetscCall(PetscMPIIntCast(nLen, &n));
143:       PetscCall(VecGetBlockSize(xin, &bs));
144:       PetscCheck(bs >= 1 && bs <= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PCICE can only handle up to 3D objects, but vector dimension is %" PetscInt_FMT, bs);

146:       PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT "\n", xin->map->N / bs));
147:       for (i = 0; i < n / bs; i++) {
148:         PetscCall(PetscViewerASCIIPrintf(viewer, "%7" PetscInt_FMT "   ", vertexCount++));
149:         for (b = 0; b < bs; b++) {
150:           if (b > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " "));
151: #if !PetscDefined(USE_COMPLEX)
152:           PetscCall(PetscViewerASCIIPrintf(viewer, "% 12.5E", (double)xarray[i * bs + b]));
153: #endif
154:         }
155:         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
156:       }
157:       for (j = 1; j < size; j++) {
158:         PetscCallMPI(MPI_Recv(values, len, MPIU_SCALAR, j, tag, PetscObjectComm((PetscObject)xin), &status));
159:         PetscCallMPI(MPI_Get_count(&status, MPIU_SCALAR, &n));
160:         for (i = 0; i < n / bs; i++) {
161:           PetscCall(PetscViewerASCIIPrintf(viewer, "%7" PetscInt_FMT "   ", vertexCount++));
162:           for (b = 0; b < bs; b++) {
163:             if (b > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " "));
164: #if !PetscDefined(USE_COMPLEX)
165:             PetscCall(PetscViewerASCIIPrintf(viewer, "% 12.5E", (double)values[i * bs + b]));
166: #endif
167:           }
168:           PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
169:         }
170:       }
171:     } else if (format == PETSC_VIEWER_ASCII_GLVIS) {
172:       /* GLVis ASCII visualization/dump: this function mimics mfem::GridFunction::Save() */
173:       const PetscScalar      *array;
174:       PetscInt                i, n, vdim, ordering = 1; /* mfem::FiniteElementSpace::Ordering::byVDIM */
175:       PetscContainer          glvis_container;
176:       PetscViewerGLVisVecInfo glvis_vec_info;
177:       PetscViewerGLVisInfo    glvis_info;

179:       /* mfem::FiniteElementSpace::Save() */
180:       PetscCall(VecGetBlockSize(xin, &vdim));
181:       PetscCall(PetscViewerASCIIPrintf(viewer, "FiniteElementSpace\n"));
182:       PetscCall(PetscObjectQuery((PetscObject)xin, "_glvis_info_container", (PetscObject *)&glvis_container));
183:       PetscCheck(glvis_container, PetscObjectComm((PetscObject)xin), PETSC_ERR_PLIB, "Missing GLVis container");
184:       PetscCall(PetscContainerGetPointer(glvis_container, &glvis_vec_info));
185:       PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", glvis_vec_info->fec_type));
186:       PetscCall(PetscViewerASCIIPrintf(viewer, "VDim: %" PetscInt_FMT "\n", vdim));
187:       PetscCall(PetscViewerASCIIPrintf(viewer, "Ordering: %" PetscInt_FMT "\n", ordering));
188:       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
189:       /* mfem::Vector::Print() */
190:       PetscCall(PetscObjectQuery((PetscObject)viewer, "_glvis_info_container", (PetscObject *)&glvis_container));
191:       PetscCheck(glvis_container, PetscObjectComm((PetscObject)viewer), PETSC_ERR_PLIB, "Missing GLVis container");
192:       PetscCall(PetscContainerGetPointer(glvis_container, &glvis_info));
193:       if (glvis_info->enabled) {
194:         PetscCall(VecGetLocalSize(xin, &n));
195:         PetscCall(VecGetArrayRead(xin, &array));
196:         for (i = 0; i < n; i++) {
197:           PetscCall(PetscViewerASCIIPrintf(viewer, glvis_info->fmt, (double)PetscRealPart(array[i])));
198:           PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
199:         }
200:         PetscCall(VecRestoreArrayRead(xin, &array));
201:       }
202:     } else if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
203:       /* No info */
204:     } else {
205:       if (format != PETSC_VIEWER_ASCII_COMMON) PetscCall(PetscViewerASCIIPrintf(viewer, "Process [%d]\n", rank));
206:       cnt = 0;
207:       for (i = 0; i < xin->map->n; i++) {
208:         if (format == PETSC_VIEWER_ASCII_INDEX) PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": ", cnt++));
209:         if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(xarray[i]) > 0.0) {
210:           PetscCall(PetscViewerASCIIPrintf(viewer, "%g + %g i\n", (double)PetscRealPart(xarray[i]), (double)PetscImaginaryPart(xarray[i])));
211:         } else if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(xarray[i]) < 0.0) {
212:           PetscCall(PetscViewerASCIIPrintf(viewer, "%g - %g i\n", (double)PetscRealPart(xarray[i]), -(double)PetscImaginaryPart(xarray[i])));
213:         } else {
214:           PetscCall(PetscViewerASCIIPrintf(viewer, "%g\n", (double)PetscRealPart(xarray[i])));
215:         }
216:       }
217:       /* receive and print messages */
218:       for (j = 1; j < size; j++) {
219:         PetscCallMPI(MPI_Recv(values, len, MPIU_SCALAR, j, tag, PetscObjectComm((PetscObject)xin), &status));
220:         PetscCallMPI(MPI_Get_count(&status, MPIU_SCALAR, &n));
221:         if (format != PETSC_VIEWER_ASCII_COMMON) PetscCall(PetscViewerASCIIPrintf(viewer, "Process [%d]\n", j));
222:         for (i = 0; i < n; i++) {
223:           if (format == PETSC_VIEWER_ASCII_INDEX) PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": ", cnt++));
224:           if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(values[i]) > 0.0) {
225:             PetscCall(PetscViewerASCIIPrintf(viewer, "%g + %g i\n", (double)PetscRealPart(values[i]), (double)PetscImaginaryPart(values[i])));
226:           } else if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(values[i]) < 0.0) {
227:             PetscCall(PetscViewerASCIIPrintf(viewer, "%g - %g i\n", (double)PetscRealPart(values[i]), -(double)PetscImaginaryPart(values[i])));
228:           } else {
229:             PetscCall(PetscViewerASCIIPrintf(viewer, "%g\n", (double)PetscRealPart(values[i])));
230:           }
231:         }
232:       }
233:     }
234:     PetscCall(PetscFree(values));
235:   } else {
236:     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
237:       /* Rank 0 is not trying to receive anything, so don't send anything */
238:     } else {
239:       if (format == PETSC_VIEWER_ASCII_MATLAB) {
240:         /* this may be a collective operation so make sure everyone calls it */
241:         PetscCall(PetscObjectGetName((PetscObject)xin, &name));
242:       }
243:       PetscCallMPI(MPIU_Send((void *)xarray, xin->map->n, MPIU_SCALAR, 0, tag, PetscObjectComm((PetscObject)xin)));
244:     }
245:   }
246:   PetscCall(PetscViewerFlush(viewer));
247:   PetscCall(VecRestoreArrayRead(xin, &xarray));
248:   PetscFunctionReturn(PETSC_SUCCESS);
249: }

251: PetscErrorCode VecView_MPI_Binary(Vec xin, PetscViewer viewer)
252: {
253:   return VecView_Binary(xin, viewer);
254: }

256: #include <petscdraw.h>
257: PetscErrorCode VecView_MPI_Draw_LG(Vec xin, PetscViewer viewer)
258: {
259:   PetscDraw          draw;
260:   PetscBool          isnull;
261:   PetscDrawLG        lg;
262:   PetscMPIInt        i, size, rank, n, N, *lens = NULL, *disp = NULL;
263:   PetscReal         *values, *xx = NULL, *yy = NULL;
264:   const PetscScalar *xarray;
265:   int                colors[] = {PETSC_DRAW_RED};

267:   PetscFunctionBegin;
268:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
269:   PetscCall(PetscDrawIsNull(draw, &isnull));
270:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
271:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)xin), &rank));
272:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)xin), &size));
273:   PetscCall(PetscMPIIntCast(xin->map->n, &n));
274:   PetscCall(PetscMPIIntCast(xin->map->N, &N));

276:   PetscCall(VecGetArrayRead(xin, &xarray));
277: #if PetscDefined(USE_COMPLEX)
278:   PetscCall(PetscMalloc1(n + 1, &values));
279:   for (i = 0; i < n; i++) values[i] = PetscRealPart(xarray[i]);
280: #else
281:   values = (PetscReal *)xarray;
282: #endif
283:   if (rank == 0) {
284:     PetscCall(PetscMalloc2(N, &xx, N, &yy));
285:     for (i = 0; i < N; i++) xx[i] = (PetscReal)i;
286:     PetscCall(PetscMalloc2(size, &lens, size, &disp));
287:     for (i = 0; i < size; i++) PetscCall(PetscMPIIntCast(xin->map->range[i + 1] - xin->map->range[i], &lens[i]));
288:     for (i = 0; i < size; i++) PetscCall(PetscMPIIntCast(xin->map->range[i], &disp[i]));
289:   }
290:   PetscCallMPI(MPI_Gatherv(values, n, MPIU_REAL, yy, lens, disp, MPIU_REAL, 0, PetscObjectComm((PetscObject)xin)));
291:   PetscCall(PetscFree2(lens, disp));
292: #if PetscDefined(USE_COMPLEX)
293:   PetscCall(PetscFree(values));
294: #endif
295:   PetscCall(VecRestoreArrayRead(xin, &xarray));

297:   PetscCall(PetscViewerDrawGetDrawLG(viewer, 0, &lg));
298:   PetscCall(PetscDrawLGReset(lg));
299:   PetscCall(PetscDrawLGSetDimension(lg, 1));
300:   PetscCall(PetscDrawLGSetColors(lg, colors));
301:   if (rank == 0) {
302:     PetscCall(PetscDrawLGAddPoints(lg, N, &xx, &yy));
303:     PetscCall(PetscFree2(xx, yy));
304:   }
305:   PetscCall(PetscDrawLGDraw(lg));
306:   PetscCall(PetscDrawLGSave(lg));
307:   PetscFunctionReturn(PETSC_SUCCESS);
308: }

310: PETSC_INTERN PetscErrorCode VecView_MPI_Draw(Vec xin, PetscViewer viewer)
311: {
312:   PetscMPIInt        rank, size, tag = ((PetscObject)viewer)->tag;
313:   PetscInt           i, start, end;
314:   MPI_Status         status;
315:   PetscReal          min, max, tmp = 0.0;
316:   PetscDraw          draw;
317:   PetscBool          isnull;
318:   PetscDrawAxis      axis;
319:   const PetscScalar *xarray;

321:   PetscFunctionBegin;
322:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
323:   PetscCall(PetscDrawIsNull(draw, &isnull));
324:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
325:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)xin), &size));
326:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)xin), &rank));

328:   PetscCall(VecMin(xin, NULL, &min));
329:   PetscCall(VecMax(xin, NULL, &max));
330:   if (min == max) {
331:     min -= 1.e-5;
332:     max += 1.e-5;
333:   }

335:   PetscCall(PetscDrawCheckResizedWindow(draw));
336:   PetscCall(PetscDrawClear(draw));

338:   PetscCall(PetscDrawAxisCreate(draw, &axis));
339:   PetscCall(PetscDrawAxisSetLimits(axis, 0.0, (PetscReal)xin->map->N, min, max));
340:   PetscCall(PetscDrawAxisDraw(axis));
341:   PetscCall(PetscDrawAxisDestroy(&axis));

343:   /* draw local part of vector */
344:   PetscCall(VecGetArrayRead(xin, &xarray));
345:   PetscCall(VecGetOwnershipRange(xin, &start, &end));
346:   if (rank < size - 1) { /* send value to right */
347:     PetscCallMPI(MPI_Send((void *)&xarray[xin->map->n - 1], 1, MPIU_REAL, rank + 1, tag, PetscObjectComm((PetscObject)xin)));
348:   }
349:   if (rank) { /* receive value from right */
350:     PetscCallMPI(MPI_Recv(&tmp, 1, MPIU_REAL, rank - 1, tag, PetscObjectComm((PetscObject)xin), &status));
351:   }
352:   PetscDrawCollectiveBegin(draw);
353:   if (rank) PetscCall(PetscDrawLine(draw, (PetscReal)start - 1, tmp, (PetscReal)start, PetscRealPart(xarray[0]), PETSC_DRAW_RED));
354:   for (i = 1; i < xin->map->n; i++) PetscCall(PetscDrawLine(draw, (PetscReal)(i - 1 + start), PetscRealPart(xarray[i - 1]), (PetscReal)(i + start), PetscRealPart(xarray[i]), PETSC_DRAW_RED));
355:   PetscDrawCollectiveEnd(draw);
356:   PetscCall(VecRestoreArrayRead(xin, &xarray));

358:   PetscCall(PetscDrawFlush(draw));
359:   PetscCall(PetscDrawPause(draw));
360:   PetscCall(PetscDrawSave(draw));
361:   PetscFunctionReturn(PETSC_SUCCESS);
362: }

364: #if PetscDefined(HAVE_MATLAB)
365: PetscErrorCode VecView_MPI_Matlab(Vec xin, PetscViewer viewer)
366: {
367:   PetscMPIInt        rank, size, *lens;
368:   PetscInt           i, N = xin->map->N;
369:   const PetscScalar *xarray;
370:   PetscScalar       *xx;

372:   PetscFunctionBegin;
373:   PetscCall(VecGetArrayRead(xin, &xarray));
374:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)xin), &rank));
375:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)xin), &size));
376:   if (rank == 0) {
377:     PetscCall(PetscMalloc1(N, &xx));
378:     PetscCall(PetscMalloc1(size, &lens));
379:     for (i = 0; i < size; i++) lens[i] = xin->map->range[i + 1] - xin->map->range[i];

381:     PetscCallMPI(MPI_Gatherv((void *)xarray, xin->map->n, MPIU_SCALAR, xx, lens, xin->map->range, MPIU_SCALAR, 0, PetscObjectComm((PetscObject)xin)));
382:     PetscCall(PetscFree(lens));

384:     PetscCall(PetscObjectName((PetscObject)xin));
385:     PetscCall(PetscViewerMatlabPutArray(viewer, N, 1, xx, ((PetscObject)xin)->name));

387:     PetscCall(PetscFree(xx));
388:   } else {
389:     PetscCallMPI(MPI_Gatherv((void *)xarray, xin->map->n, MPIU_SCALAR, 0, 0, 0, MPIU_SCALAR, 0, PetscObjectComm((PetscObject)xin)));
390:   }
391:   PetscCall(VecRestoreArrayRead(xin, &xarray));
392:   PetscFunctionReturn(PETSC_SUCCESS);
393: }
394: #endif

396: #if PetscDefined(HAVE_ADIOS)
397:   #include <adios.h>
398:   #include <adios_read.h>
399: #include <petsc/private/vieweradiosimpl.h>
400: #include <petsc/private/viewerimpl.h>

402: PetscErrorCode VecView_MPI_ADIOS(Vec xin, PetscViewer viewer)
403: {
404:   PetscViewer_ADIOS *adios = (PetscViewer_ADIOS *)viewer->data;
405:   const char        *vecname;
406:   int64_t            id;
407:   PetscInt           n, N, rstart;
408:   const PetscScalar *array;
409:   char               nglobalname[16], nlocalname[16], coffset[16];

411:   PetscFunctionBegin;
412:   PetscCall(PetscObjectGetName((PetscObject)xin, &vecname));

414:   PetscCall(VecGetLocalSize(xin, &n));
415:   PetscCall(VecGetSize(xin, &N));
416:   PetscCall(VecGetOwnershipRange(xin, &rstart, NULL));

418:   PetscCall(PetscSNPrintf(nlocalname, PETSC_STATIC_ARRAY_LENGTH(nlocalname), "%" PetscInt_FMT, n));
419:   PetscCall(PetscSNPrintf(nglobalname, PETSC_STATIC_ARRAY_LENGTH(nglobalname), "%" PetscInt_FMT, N));
420:   PetscCall(PetscSNPrintf(coffset, PETSC_STATIC_ARRAY_LENGTH(coffset), "%" PetscInt_FMT, rstart));
421:   id = adios_define_var(Petsc_adios_group, vecname, "", adios_double, nlocalname, nglobalname, coffset);
422:   PetscCall(VecGetArrayRead(xin, &array));
423:   PetscCallExternal(adios_write_byid, adios->adios_handle, id, array);
424:   PetscCall(VecRestoreArrayRead(xin, &array));
425:   PetscFunctionReturn(PETSC_SUCCESS);
426: }
427: #endif

429: #if PetscDefined(HAVE_HDF5)
430: PetscErrorCode VecView_MPI_HDF5(Vec xin, PetscViewer viewer)
431: {
432:   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
433:   /* TODO: It looks like we can remove the H5Sclose(filespace) and H5Dget_space(dset_id). Why do we do this? */
434:   hid_t              filespace;  /* file dataspace identifier */
435:   hid_t              chunkspace; /* chunk dataset property identifier */
436:   hid_t              dset_id;    /* dataset identifier */
437:   hid_t              memspace;   /* memory dataspace identifier */
438:   hid_t              file_id;
439:   hid_t              group;
440:   hid_t              memscalartype;  /* scalar type for mem (H5T_NATIVE_FLOAT or H5T_NATIVE_DOUBLE) */
441:   hid_t              filescalartype; /* scalar type for file (H5T_NATIVE_FLOAT or H5T_NATIVE_DOUBLE) */
442:   PetscInt           bs = xin->map->bs;
443:   hsize_t            dim;
444:   hsize_t            maxDims[4], dims[4], chunkDims[4], count[4], offset[4];
445:   PetscBool          timestepping, dim2, spoutput;
446:   PetscInt           timestep = PETSC_INT_MIN, low;
447:   hsize_t            chunksize;
448:   const PetscScalar *x;
449:   const char        *vecname;
450:   size_t             len;

452:   PetscFunctionBegin;
453:   PetscCall(PetscViewerHDF5OpenGroup(viewer, NULL, &file_id, &group));
454:   PetscCall(PetscViewerHDF5IsTimestepping(viewer, &timestepping));
455:   if (timestepping) PetscCall(PetscViewerHDF5GetTimestep(viewer, &timestep));
456:   PetscCall(PetscViewerHDF5GetBaseDimension2(viewer, &dim2));
457:   PetscCall(PetscViewerHDF5GetSPOutput(viewer, &spoutput));

459:   /* Create the dataspace for the dataset.
460:    *
461:    * dims - holds the current dimensions of the dataset
462:    *
463:    * maxDims - holds the maximum dimensions of the dataset (unlimited
464:    * for the number of time steps with the current dimensions for the
465:    * other dimensions; so only additional time steps can be added).
466:    *
467:    * chunkDims - holds the size of a single time step (required to
468:    * permit extending dataset).
469:    */
470:   dim       = 0;
471:   chunksize = 1;
472:   if (timestep >= 0) {
473:     dims[dim]      = timestep + 1;
474:     maxDims[dim]   = H5S_UNLIMITED;
475:     chunkDims[dim] = 1;
476:     ++dim;
477:   }
478:   PetscCall(PetscHDF5IntCast(xin->map->N / bs, dims + dim));

480:   maxDims[dim]   = dims[dim];
481:   chunkDims[dim] = PetscMax(1, dims[dim]);
482:   chunksize *= chunkDims[dim];
483:   ++dim;
484:   if (bs > 1 || dim2) {
485:     dims[dim]      = bs;
486:     maxDims[dim]   = dims[dim];
487:     chunkDims[dim] = PetscMax(1, dims[dim]);
488:     chunksize *= chunkDims[dim];
489:     ++dim;
490:   }
491:   #if PetscDefined(USE_COMPLEX)
492:   dims[dim]      = 2;
493:   maxDims[dim]   = dims[dim];
494:   chunkDims[dim] = PetscMax(1, dims[dim]);
495:   chunksize *= chunkDims[dim];
496:   /* hdf5 chunks must be less than 4GB */
497:   if (chunksize > PETSC_HDF5_MAX_CHUNKSIZE / 64) {
498:     if (bs > 1 || dim2) {
499:       if (chunkDims[dim - 2] > (hsize_t)PetscSqrtReal((PetscReal)(PETSC_HDF5_MAX_CHUNKSIZE / 128))) chunkDims[dim - 2] = (hsize_t)PetscSqrtReal((PetscReal)(PETSC_HDF5_MAX_CHUNKSIZE / 128));
500:       if (chunkDims[dim - 1] > (hsize_t)PetscSqrtReal((PetscReal)(PETSC_HDF5_MAX_CHUNKSIZE / 128))) chunkDims[dim - 1] = (hsize_t)PetscSqrtReal((PetscReal)(PETSC_HDF5_MAX_CHUNKSIZE / 128));
501:     } else {
502:       chunkDims[dim - 1] = PETSC_HDF5_MAX_CHUNKSIZE / 128;
503:     }
504:   }
505:   ++dim;
506:   #else
507:   /* hdf5 chunks must be less than 4GB */
508:   if (chunksize > PETSC_HDF5_MAX_CHUNKSIZE / 64) {
509:     if (bs > 1 || dim2) {
510:       if (chunkDims[dim - 2] > (hsize_t)PetscSqrtReal((PetscReal)(PETSC_HDF5_MAX_CHUNKSIZE / 64))) chunkDims[dim - 2] = (hsize_t)PetscSqrtReal((PetscReal)(PETSC_HDF5_MAX_CHUNKSIZE / 64));
511:       if (chunkDims[dim - 1] > (hsize_t)PetscSqrtReal((PetscReal)(PETSC_HDF5_MAX_CHUNKSIZE / 64))) chunkDims[dim - 1] = (hsize_t)PetscSqrtReal((PetscReal)(PETSC_HDF5_MAX_CHUNKSIZE / 64));
512:     } else {
513:       chunkDims[dim - 1] = PETSC_HDF5_MAX_CHUNKSIZE / 64;
514:     }
515:   }
516:   #endif

518:   PetscCallHDF5Return(filespace, H5Screate_simple, ((int)dim, dims, maxDims));

520:   #if PetscDefined(USE_REAL_SINGLE)
521:   memscalartype  = H5T_NATIVE_FLOAT;
522:   filescalartype = H5T_NATIVE_FLOAT;
523:   #elif PetscDefined(USE_REAL___FLOAT128)
524:     #error "HDF5 output with 128 bit floats not supported."
525:   #elif PetscDefined(USE_REAL___FP16)
526:     #error "HDF5 output with 16 bit floats not supported."
527:   #else
528:   memscalartype = H5T_NATIVE_DOUBLE;
529:   if (spoutput == PETSC_TRUE) filescalartype = H5T_NATIVE_FLOAT;
530:   else filescalartype = H5T_NATIVE_DOUBLE;
531:   #endif

533:   /* Create the dataset with default properties and close filespace */
534:   PetscCall(PetscObjectGetName((PetscObject)xin, &vecname));
535:   PetscCall(PetscStrlen(vecname, &len));
536:   PetscCheck(len, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONG, "Object must be named");
537:   if (H5Lexists(group, vecname, H5P_DEFAULT) < 1) {
538:     /* Create chunk */
539:     PetscCallHDF5Return(chunkspace, H5Pcreate, (H5P_DATASET_CREATE));
540:     PetscCallHDF5(H5Pset_chunk, (chunkspace, (int)dim, chunkDims));

542:     PetscCallHDF5Return(dset_id, H5Dcreate2, (group, vecname, filescalartype, filespace, H5P_DEFAULT, chunkspace, H5P_DEFAULT));
543:     PetscCallHDF5(H5Pclose, (chunkspace));
544:   } else {
545:     PetscCallHDF5Return(dset_id, H5Dopen2, (group, vecname, H5P_DEFAULT));
546:     PetscCallHDF5(H5Dset_extent, (dset_id, dims));
547:   }
548:   PetscCallHDF5(H5Sclose, (filespace));

550:   /* Each process defines a dataset and writes it to the hyperslab in the file */
551:   dim = 0;
552:   if (timestep >= 0) {
553:     count[dim] = 1;
554:     ++dim;
555:   }
556:   PetscCall(PetscHDF5IntCast(xin->map->n / bs, count + dim));
557:   ++dim;
558:   if (bs > 1 || dim2) {
559:     count[dim] = bs;
560:     ++dim;
561:   }
562:   if (PetscDefined(USE_COMPLEX)) count[dim++] = 2;
563:   if (xin->map->n > 0 || H5_VERSION_GE(1, 10, 0)) {
564:     PetscCallHDF5Return(memspace, H5Screate_simple, ((int)dim, count, NULL));
565:   } else {
566:     /* Can't create dataspace with zero for any dimension, so create null dataspace. */
567:     PetscCallHDF5Return(memspace, H5Screate, (H5S_NULL));
568:   }

570:   /* Select hyperslab in the file */
571:   PetscCall(VecGetOwnershipRange(xin, &low, NULL));
572:   dim = 0;
573:   if (timestep >= 0) {
574:     offset[dim] = timestep;
575:     ++dim;
576:   }
577:   PetscCall(PetscHDF5IntCast(low / bs, offset + dim));
578:   ++dim;
579:   if (bs > 1 || dim2) {
580:     offset[dim] = 0;
581:     ++dim;
582:   }
583:   if (PetscDefined(USE_COMPLEX)) offset[dim++] = 0;
584:   if (xin->map->n > 0 || H5_VERSION_GE(1, 10, 0)) {
585:     PetscCallHDF5Return(filespace, H5Dget_space, (dset_id));
586:     PetscCallHDF5(H5Sselect_hyperslab, (filespace, H5S_SELECT_SET, offset, NULL, count, NULL));
587:   } else {
588:     /* Create null filespace to match null memspace. */
589:     PetscCallHDF5Return(filespace, H5Screate, (H5S_NULL));
590:   }

592:   PetscCall(VecGetArrayRead(xin, &x));
593:   PetscCallHDF5(H5Dwrite, (dset_id, memscalartype, memspace, filespace, hdf5->dxpl_id, x));
594:   PetscCallHDF5(H5Fflush, (file_id, H5F_SCOPE_GLOBAL));
595:   PetscCall(VecRestoreArrayRead(xin, &x));

597:   /* Close/release resources */
598:   PetscCallHDF5(H5Gclose, (group));
599:   PetscCallHDF5(H5Sclose, (filespace));
600:   PetscCallHDF5(H5Sclose, (memspace));
601:   PetscCallHDF5(H5Dclose, (dset_id));

603:   if (PetscDefined(USE_COMPLEX)) {
604:     PetscBool tru = PETSC_TRUE;
605:     PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)xin, "complex", PETSC_BOOL, &tru));
606:   }
607:   if (timestepping) PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)xin, "timestepping", PETSC_BOOL, &timestepping));
608:   PetscCall(PetscInfo(xin, "Wrote Vec object with name %s\n", vecname));
609:   PetscFunctionReturn(PETSC_SUCCESS);
610: }
611: #endif

613: PetscErrorCode VecView_MPI(Vec xin, PetscViewer viewer)
614: {
615:   PetscBool isascii, isbinary, isdraw;
616: #if PetscDefined(HAVE_HDF5)
617:   PetscBool ishdf5;
618: #endif
619: #if PetscDefined(HAVE_MATLAB)
620:   PetscBool ismatlab;
621: #endif
622: #if PetscDefined(HAVE_ADIOS)
623:   PetscBool isadios;
624: #endif
625:   PetscBool isglvis;

627:   PetscFunctionBegin;
628:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
629:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
630:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
631: #if PetscDefined(HAVE_HDF5)
632:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
633: #endif
634: #if PetscDefined(HAVE_MATLAB)
635:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERMATLAB, &ismatlab));
636: #endif
637:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
638: #if PetscDefined(HAVE_ADIOS)
639:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERADIOS, &isadios));
640: #endif
641:   if (isascii) {
642:     PetscCall(VecView_MPI_ASCII(xin, viewer));
643:   } else if (isbinary) {
644:     PetscCall(VecView_MPI_Binary(xin, viewer));
645:   } else if (isdraw) {
646:     PetscViewerFormat format;
647:     PetscCall(PetscViewerGetFormat(viewer, &format));
648:     if (format == PETSC_VIEWER_DRAW_LG) {
649:       PetscCall(VecView_MPI_Draw_LG(xin, viewer));
650:     } else {
651:       PetscCall(VecView_MPI_Draw(xin, viewer));
652:     }
653: #if PetscDefined(HAVE_HDF5)
654:   } else if (ishdf5) {
655:     PetscCall(VecView_MPI_HDF5(xin, viewer));
656: #endif
657: #if PetscDefined(HAVE_ADIOS)
658:   } else if (isadios) {
659:     PetscCall(VecView_MPI_ADIOS(xin, viewer));
660: #endif
661: #if PetscDefined(HAVE_MATLAB)
662:   } else if (ismatlab) {
663:     PetscCall(VecView_MPI_Matlab(xin, viewer));
664: #endif
665:   } else if (isglvis) PetscCall(VecView_GLVis(xin, viewer));
666:   PetscFunctionReturn(PETSC_SUCCESS);
667: }

669: PetscErrorCode VecGetSize_MPI(Vec xin, PetscInt *N)
670: {
671:   PetscFunctionBegin;
672:   *N = xin->map->N;
673:   PetscFunctionReturn(PETSC_SUCCESS);
674: }

676: PetscErrorCode VecGetValues_MPI(Vec xin, PetscInt ni, const PetscInt ix[], PetscScalar y[])
677: {
678:   const PetscScalar *xx;
679:   const PetscInt     start = xin->map->range[xin->stash.rank];

681:   PetscFunctionBegin;
682:   PetscCall(VecGetArrayRead(xin, &xx));
683:   for (PetscInt i = 0; i < ni; i++) {
684:     if (xin->stash.ignorenegidx && ix[i] < 0) continue;
685:     const PetscInt tmp = ix[i] - start;

687:     PetscCheck(tmp >= 0 && tmp < xin->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Can only get local values, trying %" PetscInt_FMT, ix[i]);
688:     y[i] = xx[tmp];
689:   }
690:   PetscCall(VecRestoreArrayRead(xin, &xx));
691:   PetscFunctionReturn(PETSC_SUCCESS);
692: }

694: PetscErrorCode VecSetValues_MPI(Vec xin, PetscInt ni, const PetscInt ix[], const PetscScalar y[], InsertMode addv)
695: {
696:   const PetscBool   ignorenegidx = xin->stash.ignorenegidx;
697:   const PetscBool   donotstash   = xin->stash.donotstash;
698:   const PetscMPIInt rank         = xin->stash.rank;
699:   const PetscInt   *owners       = xin->map->range;
700:   const PetscInt    start = owners[rank], end = owners[rank + 1];
701:   PetscScalar      *xx;

703:   PetscFunctionBegin;
704:   if (PetscDefined(USE_DEBUG)) {
705:     PetscCheck(xin->stash.insertmode != INSERT_VALUES || addv != ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "You have already inserted values; you cannot now add");
706:     PetscCheck(xin->stash.insertmode != ADD_VALUES || addv != INSERT_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "You have already added values; you cannot now insert");
707:   }
708:   PetscCall(VecGetArray(xin, &xx));
709:   xin->stash.insertmode = addv;
710:   for (PetscInt i = 0; i < ni; ++i) {
711:     PetscInt    row;
712:     PetscScalar yv = y ? y[i] : 0;

714:     if (ignorenegidx && ix[i] < 0) continue;
715:     PetscCheck(ix[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Out of range index value %" PetscInt_FMT " cannot be negative", ix[i]);
716:     if ((row = ix[i]) >= start && row < end) {
717:       if (addv == INSERT_VALUES) {
718:         xx[row - start] = yv;
719:       } else {
720:         xx[row - start] += yv;
721:       }
722:     } else if (!donotstash) {
723:       PetscCheck(ix[i] < xin->map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Out of range index value %" PetscInt_FMT ", should be less than %" PetscInt_FMT, ix[i], xin->map->N);
724:       PetscCall(VecStashValue_Private(&xin->stash, row, yv));
725:     }
726:   }
727:   PetscCall(VecRestoreArray(xin, &xx));
728:   PetscFunctionReturn(PETSC_SUCCESS);
729: }

731: PetscErrorCode VecSetValuesBlocked_MPI(Vec xin, PetscInt ni, const PetscInt ix[], const PetscScalar yin[], InsertMode addv)
732: {
733:   PetscMPIInt  rank   = xin->stash.rank;
734:   PetscInt    *owners = xin->map->range, start = owners[rank];
735:   PetscInt     end = owners[rank + 1], i, row, bs = xin->map->bs, j;
736:   PetscScalar *xx, *y = (PetscScalar *)yin;

738:   PetscFunctionBegin;
739:   PetscCall(VecGetArray(xin, &xx));
740:   if (PetscDefined(USE_DEBUG)) {
741:     PetscCheck(xin->stash.insertmode != INSERT_VALUES || addv != ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "You have already inserted values; you cannot now add");
742:     PetscCheck(xin->stash.insertmode != ADD_VALUES || addv != INSERT_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "You have already added values; you cannot now insert");
743:   }
744:   xin->stash.insertmode = addv;

746:   if (addv == INSERT_VALUES) {
747:     for (i = 0; i < ni; i++) {
748:       if ((row = bs * ix[i]) >= start && row < end) {
749:         for (j = 0; j < bs; j++) xx[row - start + j] = y ? y[j] : 0.0;
750:       } else if (!xin->stash.donotstash) {
751:         if (ix[i] < 0) {
752:           if (y) y += bs;
753:           continue;
754:         }
755:         PetscCheck(ix[i] < xin->map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Out of range index value %" PetscInt_FMT ", should be less than %" PetscInt_FMT, ix[i], xin->map->N);
756:         PetscCall(VecStashValuesBlocked_Private(&xin->bstash, ix[i], y));
757:       }
758:       if (y) y += bs;
759:     }
760:   } else {
761:     for (i = 0; i < ni; i++) {
762:       if ((row = bs * ix[i]) >= start && row < end) {
763:         for (j = 0; j < bs; j++) xx[row - start + j] += y ? y[j] : 0.0;
764:       } else if (!xin->stash.donotstash) {
765:         if (ix[i] < 0) {
766:           if (y) y += bs;
767:           continue;
768:         }
769:         PetscCheck(ix[i] <= xin->map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Out of range index value %" PetscInt_FMT ", should be less than %" PetscInt_FMT, ix[i], xin->map->N);
770:         PetscCall(VecStashValuesBlocked_Private(&xin->bstash, ix[i], y));
771:       }
772:       if (y) y += bs;
773:     }
774:   }
775:   PetscCall(VecRestoreArray(xin, &xx));
776:   PetscFunctionReturn(PETSC_SUCCESS);
777: }

779: /*
780:    Since nsends or nreceives may be zero we add 1 in certain mallocs
781: to make sure we never malloc an empty one.
782: */
783: PetscErrorCode VecAssemblyBegin_MPI(Vec xin)
784: {
785:   PetscInt   *owners = xin->map->range, *bowners, i, bs, nstash, reallocs;
786:   PetscMPIInt size;
787:   InsertMode  addv;
788:   MPI_Comm    comm;

790:   PetscFunctionBegin;
791:   PetscCall(PetscObjectGetComm((PetscObject)xin, &comm));
792:   if (xin->stash.donotstash) PetscFunctionReturn(PETSC_SUCCESS);

794:   PetscCallMPI(MPIU_Allreduce((PetscEnum *)&xin->stash.insertmode, (PetscEnum *)&addv, 1, MPIU_ENUM, MPI_BOR, comm));
795:   PetscCheck(addv != (ADD_VALUES | INSERT_VALUES), comm, PETSC_ERR_ARG_NOTSAMETYPE, "Some processors inserted values while others added");
796:   xin->stash.insertmode  = addv; /* in case this processor had no cache */
797:   xin->bstash.insertmode = addv; /* Block stash implicitly tracks InsertMode of scalar stash */

799:   PetscCall(VecGetBlockSize(xin, &bs));
800:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)xin), &size));
801:   if (!xin->bstash.bowners && xin->map->bs != -1) {
802:     PetscCall(PetscMalloc1(size + 1, &bowners));
803:     for (i = 0; i < size + 1; i++) bowners[i] = owners[i] / bs;
804:     xin->bstash.bowners = bowners;
805:   } else bowners = xin->bstash.bowners;

807:   PetscCall(VecStashScatterBegin_Private(&xin->stash, owners));
808:   PetscCall(VecStashScatterBegin_Private(&xin->bstash, bowners));
809:   PetscCall(VecStashGetInfo_Private(&xin->stash, &nstash, &reallocs));
810:   PetscCall(PetscInfo(xin, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs));
811:   PetscCall(VecStashGetInfo_Private(&xin->bstash, &nstash, &reallocs));
812:   PetscCall(PetscInfo(xin, "Block-Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs));
813:   PetscFunctionReturn(PETSC_SUCCESS);
814: }

816: PetscErrorCode VecAssemblyEnd_MPI(Vec vec)
817: {
818:   PetscInt     base, i, j, *row, flg, bs;
819:   PetscMPIInt  n;
820:   PetscScalar *val, *vv, *array, *xarray;

822:   PetscFunctionBegin;
823:   if (!vec->stash.donotstash) {
824:     PetscCall(VecGetArray(vec, &xarray));
825:     PetscCall(VecGetBlockSize(vec, &bs));
826:     base = vec->map->range[vec->stash.rank];

828:     /* Process the stash */
829:     while (1) {
830:       PetscCall(VecStashScatterGetMesg_Private(&vec->stash, &n, &row, &val, &flg));
831:       if (!flg) break;
832:       if (vec->stash.insertmode == ADD_VALUES) {
833:         for (i = 0; i < n; i++) xarray[row[i] - base] += val[i];
834:       } else if (vec->stash.insertmode == INSERT_VALUES) {
835:         for (i = 0; i < n; i++) xarray[row[i] - base] = val[i];
836:       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Insert mode is not set correctly; corrupted vector");
837:     }
838:     PetscCall(VecStashScatterEnd_Private(&vec->stash));

840:     /* now process the block-stash */
841:     while (1) {
842:       PetscCall(VecStashScatterGetMesg_Private(&vec->bstash, &n, &row, &val, &flg));
843:       if (!flg) break;
844:       for (i = 0; i < n; i++) {
845:         array = xarray + row[i] * bs - base;
846:         vv    = val + i * bs;
847:         if (vec->stash.insertmode == ADD_VALUES) {
848:           for (j = 0; j < bs; j++) array[j] += vv[j];
849:         } else if (vec->stash.insertmode == INSERT_VALUES) {
850:           for (j = 0; j < bs; j++) array[j] = vv[j];
851:         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Insert mode is not set correctly; corrupted vector");
852:       }
853:     }
854:     PetscCall(VecStashScatterEnd_Private(&vec->bstash));
855:     PetscCall(VecRestoreArray(vec, &xarray));
856:   }
857:   vec->stash.insertmode = NOT_SET_VALUES;
858:   PetscFunctionReturn(PETSC_SUCCESS);
859: }

861: PetscErrorCode VecSetPreallocationCOO_MPI(Vec x, PetscCount coo_n, const PetscInt coo_i[])
862: {
863:   PetscInt    m, M, rstart, rend;
864:   Vec_MPI    *vmpi = (Vec_MPI *)x->data;
865:   PetscCount  k, p, q, rem; /* Loop variables over coo arrays */
866:   PetscMPIInt size;
867:   MPI_Comm    comm;

869:   PetscFunctionBegin;
870:   PetscCall(PetscObjectGetComm((PetscObject)x, &comm));
871:   PetscCallMPI(MPI_Comm_size(comm, &size));
872:   PetscCall(VecResetPreallocationCOO_MPI(x));

874:   PetscCall(PetscLayoutSetUp(x->map));
875:   PetscCall(VecGetOwnershipRange(x, &rstart, &rend));
876:   PetscCall(VecGetLocalSize(x, &m));
877:   PetscCall(VecGetSize(x, &M));

879:   /* Sort COOs along with a permutation array, so that negative indices come    */
880:   /* first, then local ones, then remote ones.                                  */
881:   PetscCount n1 = coo_n, nneg, *perm;
882:   PetscInt  *i1; /* Copy of input COOs along with a permutation array */
883:   PetscCall(PetscMalloc1(n1, &i1));
884:   PetscCall(PetscMalloc1(n1, &perm));
885:   PetscCall(PetscArraycpy(i1, coo_i, n1)); /* Make a copy since we'll modify it */
886:   for (k = 0; k < n1; k++) perm[k] = k;

888:   /* Manipulate i1[] so that entries with negative indices will have the smallest
889:      index, local entries will have greater but negative indices, and remote entries
890:      will have positive indices.
891:   */
892:   for (k = 0; k < n1; k++) {
893:     if (i1[k] < 0) {
894:       if (x->stash.ignorenegidx) i1[k] = PETSC_INT_MIN; /* e.g., -2^31, minimal to move them ahead */
895:       else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Found a negative index in VecSetPreallocateCOO() but VEC_IGNORE_NEGATIVE_INDICES was not set");
896:     } else if (i1[k] >= rstart && i1[k] < rend) {
897:       i1[k] -= PETSC_INT_MAX; /* e.g., minus 2^31-1 to shift local rows to range of [-PETSC_INT_MAX, -1] */
898:     } else {
899:       PetscCheck(i1[k] < M, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Found index %" PetscInt_FMT " in VecSetPreallocateCOO() larger than the global size %" PetscInt_FMT, i1[k], M);
900:       if (x->stash.donotstash) i1[k] = PETSC_INT_MIN; /* Ignore off-proc indices as if they were negative */
901:     }
902:   }

904:   /* Sort the indices, after that, [0,nneg) have ignored entries, [nneg,rem) have local entries and [rem,n1) have remote entries */
905:   PetscCall(PetscSortIntWithCountArray(n1, i1, perm));
906:   for (k = 0; k < n1; k++) {
907:     if (i1[k] > PETSC_INT_MIN) break;
908:   } /* Advance k to the first entry we need to take care of */
909:   nneg = k;
910:   PetscCall(PetscSortedIntUpperBound(i1, nneg, n1, rend - 1 - PETSC_INT_MAX, &rem)); /* rem is upper bound of the last local row */
911:   for (k = nneg; k < rem; k++) i1[k] += PETSC_INT_MAX;                               /* Revert indices of local entries */

913:   /*           Build stuff for local entries                                    */
914:   PetscCount tot1, *jmap1, *perm1;
915:   PetscCall(PetscCalloc1(m + 1, &jmap1));
916:   for (k = nneg; k < rem; k++) jmap1[i1[k] - rstart + 1]++; /* Count repeats of each local entry */
917:   for (k = 0; k < m; k++) jmap1[k + 1] += jmap1[k];         /* Transform jmap1[] to CSR-like data structure */
918:   tot1 = jmap1[m];
919:   PetscAssert(tot1 == rem - nneg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected errors in VecSetPreallocationCOO_MPI");
920:   PetscCall(PetscMalloc1(tot1, &perm1));
921:   PetscCall(PetscArraycpy(perm1, perm + nneg, tot1));

923:   /*        Record the permutation array for filling the send buffer            */
924:   PetscCount *Cperm;
925:   PetscCall(PetscMalloc1(n1 - rem, &Cperm));
926:   PetscCall(PetscArraycpy(Cperm, perm + rem, n1 - rem));
927:   PetscCall(PetscFree(perm));

929:   /*           Send remote entries to their owner                                  */
930:   /* Find which entries should be sent to which remote ranks*/
931:   PetscInt        nsend = 0; /* Number of MPI ranks to send data to */
932:   PetscMPIInt    *sendto;    /* [nsend], storing remote ranks */
933:   PetscInt       *nentries;  /* [nsend], storing number of entries sent to remote ranks; Assume PetscInt is big enough for this count, and error if not */
934:   const PetscInt *ranges;
935:   PetscInt        maxNsend = size >= 128 ? 128 : size; /* Assume max 128 neighbors; realloc when needed */

937:   PetscCall(PetscLayoutGetRanges(x->map, &ranges));
938:   PetscCall(PetscMalloc2(maxNsend, &sendto, maxNsend, &nentries));
939:   for (k = rem; k < n1;) {
940:     PetscMPIInt owner;
941:     PetscInt    firstRow, lastRow;

943:     /* Locate a row range */
944:     firstRow = i1[k]; /* first row of this owner */
945:     PetscCall(PetscLayoutFindOwner(x->map, firstRow, &owner));
946:     lastRow = ranges[owner + 1] - 1; /* last row of this owner */

948:     /* Find the first index 'p' in [k,n) with i[p] belonging to next owner */
949:     PetscCall(PetscSortedIntUpperBound(i1, k, n1, lastRow, &p));

951:     /* All entries in [k,p) belong to this remote owner */
952:     if (nsend >= maxNsend) { /* Double the remote ranks arrays if not long enough */
953:       PetscMPIInt *sendto2;
954:       PetscInt    *nentries2;
955:       PetscInt     maxNsend2 = (maxNsend <= size / 2) ? maxNsend * 2 : size;

957:       PetscCall(PetscMalloc2(maxNsend2, &sendto2, maxNsend2, &nentries2));
958:       PetscCall(PetscArraycpy(sendto2, sendto, maxNsend));
959:       PetscCall(PetscArraycpy(nentries2, nentries2, maxNsend + 1));
960:       PetscCall(PetscFree2(sendto, nentries2));
961:       sendto   = sendto2;
962:       nentries = nentries2;
963:       maxNsend = maxNsend2;
964:     }
965:     sendto[nsend] = owner;
966:     PetscCall(PetscIntCast(p - k, &nentries[nsend]));
967:     nsend++;
968:     k = p;
969:   }

971:   /* Build 1st SF to know offsets on remote to send data */
972:   PetscSF      sf1;
973:   PetscInt     nroots = 1, nroots2 = 0;
974:   PetscInt     nleaves = nsend, nleaves2 = 0;
975:   PetscInt    *offsets;
976:   PetscSFNode *iremote;

978:   PetscCall(PetscSFCreate(comm, &sf1));
979:   PetscCall(PetscMalloc1(nsend, &iremote));
980:   PetscCall(PetscMalloc1(nsend, &offsets));
981:   for (k = 0; k < nsend; k++) {
982:     iremote[k].rank  = sendto[k];
983:     iremote[k].index = 0;
984:     nleaves2 += nentries[k];
985:     PetscCheck(nleaves2 >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of SF leaves is too large for PetscInt");
986:   }
987:   PetscCall(PetscSFSetGraph(sf1, nroots, nleaves, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
988:   PetscCall(PetscSFFetchAndOpWithMemTypeBegin(sf1, MPIU_INT, PETSC_MEMTYPE_HOST, &nroots2 /*rootdata*/, PETSC_MEMTYPE_HOST, nentries /*leafdata*/, PETSC_MEMTYPE_HOST, offsets /*leafupdate*/, MPI_SUM));
989:   PetscCall(PetscSFFetchAndOpEnd(sf1, MPIU_INT, &nroots2, nentries, offsets, MPI_SUM)); /* Would nroots2 overflow, we check offsets[] below */
990:   PetscCall(PetscSFDestroy(&sf1));
991:   PetscAssert(nleaves2 == n1 - rem, PETSC_COMM_SELF, PETSC_ERR_PLIB, "nleaves2 %" PetscInt_FMT " != number of remote entries %" PetscCount_FMT, nleaves2, n1 - rem);

993:   /* Build 2nd SF to send remote COOs to their owner */
994:   PetscSF sf2;
995:   nroots  = nroots2;
996:   nleaves = nleaves2;
997:   PetscCall(PetscSFCreate(comm, &sf2));
998:   PetscCall(PetscSFSetFromOptions(sf2));
999:   PetscCall(PetscMalloc1(nleaves, &iremote));
1000:   p = 0;
1001:   for (k = 0; k < nsend; k++) {
1002:     PetscCheck(offsets[k] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of SF roots is too large for PetscInt");
1003:     for (q = 0; q < nentries[k]; q++, p++) {
1004:       iremote[p].rank = sendto[k];
1005:       PetscCall(PetscIntCast(offsets[k] + q, &iremote[p].index));
1006:     }
1007:   }
1008:   PetscCall(PetscSFSetGraph(sf2, nroots, nleaves, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));

1010:   /* Send the remote COOs to their owner */
1011:   PetscInt    n2 = nroots, *i2; /* Buffers for received COOs from other ranks, along with a permutation array */
1012:   PetscCount *perm2;
1013:   PetscCall(PetscMalloc1(n2, &i2));
1014:   PetscCall(PetscMalloc1(n2, &perm2));
1015:   PetscCall(PetscSFReduceWithMemTypeBegin(sf2, MPIU_INT, PETSC_MEMTYPE_HOST, i1 + rem, PETSC_MEMTYPE_HOST, i2, MPI_REPLACE));
1016:   PetscCall(PetscSFReduceEnd(sf2, MPIU_INT, i1 + rem, i2, MPI_REPLACE));

1018:   PetscCall(PetscFree(i1));
1019:   PetscCall(PetscFree(offsets));
1020:   PetscCall(PetscFree2(sendto, nentries));

1022:   /* Sort received COOs along with a permutation array            */
1023:   PetscCount  *imap2;
1024:   PetscCount  *jmap2, nnz2;
1025:   PetscScalar *sendbuf, *recvbuf;
1026:   PetscInt     old;
1027:   PetscCount   sendlen = n1 - rem, recvlen = n2;

1029:   for (k = 0; k < n2; k++) perm2[k] = k;
1030:   PetscCall(PetscSortIntWithCountArray(n2, i2, perm2));

1032:   /* nnz2 will be # of unique entries in the recvbuf */
1033:   nnz2 = n2;
1034:   for (k = 1; k < n2; k++) {
1035:     if (i2[k] == i2[k - 1]) nnz2--;
1036:   }

1038:   /* Build imap2[] and jmap2[] for each unique entry */
1039:   PetscCall(PetscMalloc4(nnz2, &imap2, nnz2 + 1, &jmap2, sendlen, &sendbuf, recvlen, &recvbuf));
1040:   p        = -1;
1041:   old      = -1;
1042:   jmap2[0] = 0;
1043:   jmap2++;
1044:   for (k = 0; k < n2; k++) {
1045:     if (i2[k] != old) { /* Meet a new entry */
1046:       p++;
1047:       imap2[p] = i2[k] - rstart;
1048:       jmap2[p] = 1;
1049:       old      = i2[k];
1050:     } else {
1051:       jmap2[p]++;
1052:     }
1053:   }
1054:   jmap2--;
1055:   for (k = 0; k < nnz2; k++) jmap2[k + 1] += jmap2[k];

1057:   PetscCall(PetscFree(i2));

1059:   vmpi->coo_n = coo_n;
1060:   vmpi->tot1  = tot1;
1061:   vmpi->jmap1 = jmap1;
1062:   vmpi->perm1 = perm1;
1063:   vmpi->nnz2  = nnz2;
1064:   vmpi->imap2 = imap2;
1065:   vmpi->jmap2 = jmap2;
1066:   vmpi->perm2 = perm2;

1068:   vmpi->Cperm   = Cperm;
1069:   vmpi->sendbuf = sendbuf;
1070:   vmpi->recvbuf = recvbuf;
1071:   vmpi->sendlen = sendlen;
1072:   vmpi->recvlen = recvlen;
1073:   vmpi->coo_sf  = sf2;
1074:   PetscFunctionReturn(PETSC_SUCCESS);
1075: }

1077: PetscErrorCode VecSetValuesCOO_MPI(Vec x, const PetscScalar v[], InsertMode imode)
1078: {
1079:   Vec_MPI          *vmpi = (Vec_MPI *)x->data;
1080:   PetscInt          m;
1081:   PetscScalar      *a, *sendbuf = vmpi->sendbuf, *recvbuf = vmpi->recvbuf;
1082:   const PetscCount *jmap1 = vmpi->jmap1;
1083:   const PetscCount *perm1 = vmpi->perm1;
1084:   const PetscCount *imap2 = vmpi->imap2;
1085:   const PetscCount *jmap2 = vmpi->jmap2;
1086:   const PetscCount *perm2 = vmpi->perm2;
1087:   const PetscCount *Cperm = vmpi->Cperm;
1088:   const PetscCount  nnz2  = vmpi->nnz2;

1090:   PetscFunctionBegin;
1091:   PetscCall(VecGetLocalSize(x, &m));
1092:   PetscCall(VecGetArray(x, &a));

1094:   /* Pack entries to be sent to remote */
1095:   for (PetscInt i = 0; i < vmpi->sendlen; i++) sendbuf[i] = v[Cperm[i]];

1097:   /* Send remote entries to their owner and overlap the communication with local computation */
1098:   PetscCall(PetscSFReduceWithMemTypeBegin(vmpi->coo_sf, MPIU_SCALAR, PETSC_MEMTYPE_HOST, sendbuf, PETSC_MEMTYPE_HOST, recvbuf, MPI_REPLACE));
1099:   /* Add local entries to A and B */
1100:   for (PetscInt i = 0; i < m; i++) { /* All entries in a[] are either zero'ed or added with a value (i.e., initialized) */
1101:     PetscScalar sum = 0.0;           /* Do partial summation first to improve numerical stability */
1102:     for (PetscCount k = jmap1[i]; k < jmap1[i + 1]; k++) sum += v[perm1[k]];
1103:     a[i] = (imode == INSERT_VALUES ? 0.0 : a[i]) + sum;
1104:   }
1105:   PetscCall(PetscSFReduceEnd(vmpi->coo_sf, MPIU_SCALAR, sendbuf, recvbuf, MPI_REPLACE));

1107:   /* Add received remote entries to A and B */
1108:   for (PetscInt i = 0; i < nnz2; i++) {
1109:     for (PetscCount k = jmap2[i]; k < jmap2[i + 1]; k++) a[imap2[i]] += recvbuf[perm2[k]];
1110:   }

1112:   PetscCall(VecRestoreArray(x, &a));
1113:   PetscFunctionReturn(PETSC_SUCCESS);
1114: }