Actual source code: bvec2.c

  1: /*
  2:    Implements the sequential vectors.
  3: */

  5: #include <../src/vec/vec/impls/dvecimpl.h>
  6: #include <../src/vec/vec/impls/mpi/pvecimpl.h>
  7: #include <petsc/private/glvisviewerimpl.h>
  8: #include <petsc/private/glvisvecimpl.h>
  9: #include <petscblaslapack.h>

 11: static PetscErrorCode VecPointwiseApply_Seq(Vec win, Vec xin, Vec yin, PetscScalar (*const func)(PetscScalar, PetscScalar))
 12: {
 13:   const PetscInt n = win->map->n;
 14:   PetscScalar   *ww, *xx, *yy; /* cannot make xx or yy const since might be ww */

 16:   PetscFunctionBegin;
 17:   PetscCall(VecGetArrayRead(xin, (const PetscScalar **)&xx));
 18:   PetscCall(VecGetArrayRead(yin, (const PetscScalar **)&yy));
 19:   PetscCall(VecGetArray(win, &ww));
 20:   for (PetscInt i = 0; i < n; ++i) ww[i] = func(xx[i], yy[i]);
 21:   PetscCall(VecRestoreArrayRead(xin, (const PetscScalar **)&xx));
 22:   PetscCall(VecRestoreArrayRead(yin, (const PetscScalar **)&yy));
 23:   PetscCall(VecRestoreArray(win, &ww));
 24:   PetscCall(PetscLogFlops(n));
 25:   PetscFunctionReturn(PETSC_SUCCESS);
 26: }

 28: static PetscScalar MaxRealPart(PetscScalar x, PetscScalar y)
 29: {
 30:   // use temporaries to avoid reevaluating side-effects
 31:   const PetscReal rx = PetscRealPart(x), ry = PetscRealPart(y);

 33:   return PetscMax(rx, ry);
 34: }

 36: PetscErrorCode VecPointwiseMax_Seq(Vec win, Vec xin, Vec yin)
 37: {
 38:   PetscFunctionBegin;
 39:   PetscCall(VecPointwiseApply_Seq(win, xin, yin, MaxRealPart));
 40:   PetscFunctionReturn(PETSC_SUCCESS);
 41: }

 43: static PetscScalar MinRealPart(PetscScalar x, PetscScalar y)
 44: {
 45:   // use temporaries to avoid reevaluating side-effects
 46:   const PetscReal rx = PetscRealPart(x), ry = PetscRealPart(y);

 48:   return PetscMin(rx, ry);
 49: }

 51: PetscErrorCode VecPointwiseMin_Seq(Vec win, Vec xin, Vec yin)
 52: {
 53:   PetscFunctionBegin;
 54:   PetscCall(VecPointwiseApply_Seq(win, xin, yin, MinRealPart));
 55:   PetscFunctionReturn(PETSC_SUCCESS);
 56: }

 58: static PetscScalar MaxAbs(PetscScalar x, PetscScalar y)
 59: {
 60:   return PetscMax(PetscAbsScalar(x), PetscAbsScalar(y));
 61: }

 63: PetscErrorCode VecPointwiseMaxAbs_Seq(Vec win, Vec xin, Vec yin)
 64: {
 65:   PetscFunctionBegin;
 66:   PetscCall(VecPointwiseApply_Seq(win, xin, yin, MaxAbs));
 67:   PetscFunctionReturn(PETSC_SUCCESS);
 68: }

 70: #include <../src/vec/vec/impls/seq/ftn-kernels/fxtimesy.h>

 72: PetscErrorCode VecPointwiseMult_Seq(Vec win, Vec xin, Vec yin)
 73: {
 74:   PetscInt     n = win->map->n, i;
 75:   PetscScalar *ww, *xx, *yy; /* cannot make xx or yy const since might be ww */

 77:   PetscFunctionBegin;
 78:   PetscCall(VecGetArrayRead(xin, (const PetscScalar **)&xx));
 79:   PetscCall(VecGetArrayRead(yin, (const PetscScalar **)&yy));
 80:   PetscCall(VecGetArray(win, &ww));
 81:   if (ww == xx) {
 82:     for (i = 0; i < n; i++) ww[i] *= yy[i];
 83:   } else if (ww == yy) {
 84:     for (i = 0; i < n; i++) ww[i] *= xx[i];
 85:   } else {
 86: #if PetscDefined(USE_FORTRAN_KERNEL_XTIMESY)
 87:     fortranxtimesy_(xx, yy, ww, &n);
 88: #else
 89:     for (i = 0; i < n; i++) ww[i] = xx[i] * yy[i];
 90: #endif
 91:   }
 92:   PetscCall(VecRestoreArrayRead(xin, (const PetscScalar **)&xx));
 93:   PetscCall(VecRestoreArrayRead(yin, (const PetscScalar **)&yy));
 94:   PetscCall(VecRestoreArray(win, &ww));
 95:   PetscCall(PetscLogFlops(n));
 96:   PetscFunctionReturn(PETSC_SUCCESS);
 97: }

 99: static PetscScalar ScalDiv(PetscScalar x, PetscScalar y)
100: {
101:   return y == 0.0 ? (x == 0.0 ? 1.0 : 0.0) : x / y;
102: }

104: PetscErrorCode VecPointwiseDivide_Seq(Vec win, Vec xin, Vec yin)
105: {
106:   PetscFunctionBegin;
107:   PetscCall(VecPointwiseApply_Seq(win, xin, yin, ScalDiv));
108:   PetscFunctionReturn(PETSC_SUCCESS);
109: }

111: PetscErrorCode VecSetRandom_Seq(Vec xin, PetscRandom r)
112: {
113:   PetscScalar *xx;

115:   PetscFunctionBegin;
116:   PetscCall(VecGetArrayWrite(xin, &xx));
117:   PetscCall(PetscRandomGetValues(r, xin->map->n, xx));
118:   PetscCall(VecRestoreArrayWrite(xin, &xx));
119:   PetscFunctionReturn(PETSC_SUCCESS);
120: }

122: PetscErrorCode VecGetSize_Seq(Vec vin, PetscInt *size)
123: {
124:   PetscFunctionBegin;
125:   *size = vin->map->n;
126:   PetscFunctionReturn(PETSC_SUCCESS);
127: }

129: PetscErrorCode VecConjugate_Seq(Vec xin)
130: {
131:   const PetscInt n = xin->map->n;
132:   PetscScalar   *x;

134:   PetscFunctionBegin;
135:   PetscCall(VecGetArray(xin, &x));
136:   for (PetscInt i = 0; i < n; ++i) x[i] = PetscConj(x[i]);
137:   PetscCall(VecRestoreArray(xin, &x));
138:   PetscFunctionReturn(PETSC_SUCCESS);
139: }

141: PetscErrorCode VecResetArray_Seq(Vec vin)
142: {
143:   Vec_Seq *v = (Vec_Seq *)vin->data;

145:   PetscFunctionBegin;
146:   v->array         = v->unplacedarray;
147:   v->unplacedarray = NULL;
148:   PetscFunctionReturn(PETSC_SUCCESS);
149: }

151: PetscErrorCode VecCopy_Seq(Vec xin, Vec yin)
152: {
153:   PetscFunctionBegin;
154:   if (xin != yin) {
155:     const PetscScalar *xa;
156:     PetscScalar       *ya;

158:     PetscCall(VecGetArrayRead(xin, &xa));
159:     PetscCall(VecGetArrayWrite(yin, &ya));
160:     PetscCall(PetscArraycpy(ya, xa, xin->map->n));
161:     PetscCall(VecRestoreArrayRead(xin, &xa));
162:     PetscCall(VecRestoreArrayWrite(yin, &ya));
163:   }
164:   PetscFunctionReturn(PETSC_SUCCESS);
165: }

167: PetscErrorCode VecSwap_Seq(Vec xin, Vec yin)
168: {
169:   PetscFunctionBegin;
170:   if (xin != yin) {
171:     const PetscBLASInt one = 1;
172:     PetscScalar       *ya, *xa;
173:     PetscBLASInt       bn;

175:     PetscCall(PetscBLASIntCast(xin->map->n, &bn));
176:     PetscCall(VecGetArray(xin, &xa));
177:     PetscCall(VecGetArray(yin, &ya));
178:     PetscCallBLAS("BLASswap", BLASswap_(&bn, xa, &one, ya, &one));
179:     PetscCall(VecRestoreArray(xin, &xa));
180:     PetscCall(VecRestoreArray(yin, &ya));
181:   }
182:   PetscFunctionReturn(PETSC_SUCCESS);
183: }

185: PetscErrorCode VecNorm_Seq(Vec xin, NormType type, PetscReal *z)
186: {
187:   // use a local variable to ensure compiler doesn't think z aliases any of the other arrays
188:   PetscReal      ztmp[] = {0.0, 0.0};
189:   const PetscInt n      = xin->map->n;

191:   PetscFunctionBegin;
192:   if (n) {
193:     const PetscScalar *xx;
194:     const PetscBLASInt one = 1;
195:     PetscBLASInt       bn  = 0;

197:     PetscCall(PetscBLASIntCast(n, &bn));
198:     PetscCall(VecGetArrayRead(xin, &xx));
199:     if (type == NORM_2 || type == NORM_FROBENIUS) {
200:     NORM_1_AND_2_DOING_NORM_2:
201:       if (PetscDefined(USE_REAL___FP16)) {
202:         PetscCallBLAS("BLASnrm2", ztmp[type == NORM_1_AND_2] = BLASnrm2_(&bn, xx, &one));
203:       } else {
204:         PetscCallBLAS("BLASdot", ztmp[type == NORM_1_AND_2] = PetscSqrtReal(PetscRealPart(BLASdot_(&bn, xx, &one, xx, &one))));
205:       }
206:       PetscCall(PetscLogFlops(2.0 * n - 1));
207:     } else if (type == NORM_INFINITY) {
208:       for (PetscInt i = 0; i < n; ++i) {
209:         const PetscReal tmp = PetscAbsScalar(xx[i]);

211:         /* check special case of tmp == NaN */
212:         if ((tmp > ztmp[0]) || (tmp != tmp)) {
213:           ztmp[0] = tmp;
214:           if (tmp != tmp) break;
215:         }
216:       }
217:     } else if (type == NORM_1 || type == NORM_1_AND_2) {
218:       if (PetscDefined(USE_COMPLEX)) {
219:         // BLASasum() returns the nonstandard 1 norm of the 1 norm of the complex entries so we
220:         // provide a custom loop instead
221:         for (PetscInt i = 0; i < n; ++i) ztmp[0] += PetscAbsScalar(xx[i]);
222:       } else {
223:         PetscCallBLAS("BLASasum", ztmp[0] = BLASasum_(&bn, xx, &one));
224:       }
225:       PetscCall(PetscLogFlops(n - 1.0));
226:       /* slight reshuffle so we can skip getting the array again (but still log the flops) if we
227:          do norm2 after this */
228:       if (type == NORM_1_AND_2) goto NORM_1_AND_2_DOING_NORM_2;
229:     }
230:     PetscCall(VecRestoreArrayRead(xin, &xx));
231:   }
232:   z[0] = ztmp[0];
233:   if (type == NORM_1_AND_2) z[1] = ztmp[1];
234:   PetscFunctionReturn(PETSC_SUCCESS);
235: }

237: static PetscErrorCode VecView_Seq_ASCII(Vec xin, PetscViewer viewer)
238: {
239:   PetscInt           i, n = xin->map->n;
240:   const char        *name;
241:   PetscViewerFormat  format;
242:   const PetscScalar *xv;

244:   PetscFunctionBegin;
245:   PetscCall(VecGetArrayRead(xin, &xv));
246:   PetscCall(PetscViewerGetFormat(viewer, &format));
247:   if (format == PETSC_VIEWER_ASCII_MATLAB) {
248:     PetscCall(PetscObjectGetName((PetscObject)xin, &name));
249:     PetscCall(PetscViewerASCIIPrintf(viewer, "%s = [\n", name));
250:     for (i = 0; i < n; i++) {
251:       if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(xv[i]) > 0.0) {
252:         PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e + %18.16ei\n", (double)PetscRealPart(xv[i]), (double)PetscImaginaryPart(xv[i])));
253:       } else if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(xv[i]) < 0.0) {
254:         PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e - %18.16ei\n", (double)PetscRealPart(xv[i]), -(double)PetscImaginaryPart(xv[i])));
255:       } else {
256:         PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e\n", (double)PetscRealPart(xv[i])));
257:       }
258:     }
259:     PetscCall(PetscViewerASCIIPrintf(viewer, "];\n"));
260:   } else if (format == PETSC_VIEWER_ASCII_SYMMODU) {
261:     for (i = 0; i < n; i++) {
262:       if (PetscDefined(USE_COMPLEX)) PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e %18.16e\n", (double)PetscRealPart(xv[i]), (double)PetscImaginaryPart(xv[i])));
263:       else PetscCall(PetscViewerASCIIPrintf(viewer, "%18.16e\n", (double)PetscRealPart(xv[i])));
264:     }
265:   } else if (format == PETSC_VIEWER_ASCII_PCICE) {
266:     PetscInt bs;

268:     PetscCall(VecGetBlockSize(xin, &bs));
269:     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);
270:     PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT "\n", xin->map->N / bs));
271:     for (i = 0; i < n / bs; i++) {
272:       PetscCall(PetscViewerASCIIPrintf(viewer, "%7" PetscInt_FMT "   ", i + 1));
273:       for (PetscInt b = 0; b < bs; b++) {
274:         if (b > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " "));
275: #if !PetscDefined(USE_COMPLEX)
276:         PetscCall(PetscViewerASCIIPrintf(viewer, "% 12.5E", (double)xv[i * bs + b]));
277: #endif
278:       }
279:       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
280:     }
281:   } else if (format == PETSC_VIEWER_ASCII_GLVIS) {
282:     /* GLVis ASCII visualization/dump: this function mimics mfem::GridFunction::Save() */
283:     const PetscScalar      *array;
284:     PetscInt                i, n, vdim, ordering = 1; /* mfem::FiniteElementSpace::Ordering::byVDIM */
285:     PetscContainer          glvis_container;
286:     PetscViewerGLVisVecInfo glvis_vec_info;
287:     PetscViewerGLVisInfo    glvis_info;

289:     /* mfem::FiniteElementSpace::Save() */
290:     PetscCall(VecGetBlockSize(xin, &vdim));
291:     PetscCall(PetscViewerASCIIPrintf(viewer, "FiniteElementSpace\n"));
292:     PetscCall(PetscObjectQuery((PetscObject)xin, "_glvis_info_container", (PetscObject *)&glvis_container));
293:     PetscCheck(glvis_container, PetscObjectComm((PetscObject)xin), PETSC_ERR_PLIB, "Missing GLVis container");
294:     PetscCall(PetscContainerGetPointer(glvis_container, &glvis_vec_info));
295:     PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", glvis_vec_info->fec_type));
296:     PetscCall(PetscViewerASCIIPrintf(viewer, "VDim: %" PetscInt_FMT "\n", vdim));
297:     PetscCall(PetscViewerASCIIPrintf(viewer, "Ordering: %" PetscInt_FMT "\n", ordering));
298:     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
299:     /* mfem::Vector::Print() */
300:     PetscCall(PetscObjectQuery((PetscObject)viewer, "_glvis_info_container", (PetscObject *)&glvis_container));
301:     PetscCheck(glvis_container, PetscObjectComm((PetscObject)viewer), PETSC_ERR_PLIB, "Missing GLVis container");
302:     PetscCall(PetscContainerGetPointer(glvis_container, &glvis_info));
303:     if (glvis_info->enabled) {
304:       PetscCall(VecGetLocalSize(xin, &n));
305:       PetscCall(VecGetArrayRead(xin, &array));
306:       for (i = 0; i < n; i++) {
307:         PetscCall(PetscViewerASCIIPrintf(viewer, glvis_info->fmt, (double)PetscRealPart(array[i])));
308:         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
309:       }
310:       PetscCall(VecRestoreArrayRead(xin, &array));
311:     }
312:   } else if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
313:     /* No info */
314:   } else {
315:     for (i = 0; i < n; i++) {
316:       if (format == PETSC_VIEWER_ASCII_INDEX) PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": ", i));
317:       if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(xv[i]) > 0.0) {
318:         PetscCall(PetscViewerASCIIPrintf(viewer, "%g + %g i\n", (double)PetscRealPart(xv[i]), (double)PetscImaginaryPart(xv[i])));
319:       } else if (PetscDefined(USE_COMPLEX) && PetscImaginaryPart(xv[i]) < 0.0) {
320:         PetscCall(PetscViewerASCIIPrintf(viewer, "%g - %g i\n", (double)PetscRealPart(xv[i]), -(double)PetscImaginaryPart(xv[i])));
321:       } else {
322:         PetscCall(PetscViewerASCIIPrintf(viewer, "%g\n", (double)PetscRealPart(xv[i])));
323:       }
324:     }
325:   }
326:   PetscCall(PetscViewerFlush(viewer));
327:   PetscCall(VecRestoreArrayRead(xin, &xv));
328:   PetscFunctionReturn(PETSC_SUCCESS);
329: }

331: #include <petscdraw.h>
332: static PetscErrorCode VecView_Seq_Draw_LG(Vec xin, PetscViewer v)
333: {
334:   PetscDraw          draw;
335:   PetscBool          isnull;
336:   PetscDrawLG        lg;
337:   PetscInt           i, c, bs = xin->map->bs, n = xin->map->n / bs;
338:   const PetscScalar *xv;
339:   PetscReal         *xx, *yy, xmin, xmax, h;
340:   int                colors[] = {PETSC_DRAW_RED};
341:   PetscViewerFormat  format;
342:   PetscDrawAxis      axis;
343:   const char        *name;

345:   PetscFunctionBegin;
346:   PetscCall(PetscViewerDrawGetDraw(v, 0, &draw));
347:   PetscCall(PetscDrawIsNull(draw, &isnull));
348:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);

350:   PetscCall(PetscObjectGetName((PetscObject)xin, &name));
351:   PetscCall(PetscDrawSetTitle(draw, name));
352:   PetscCall(PetscViewerGetFormat(v, &format));
353:   PetscCall(PetscMalloc2(n, &xx, n, &yy));
354:   PetscCall(VecGetArrayRead(xin, &xv));
355:   for (c = 0; c < bs; c++) {
356:     PetscCall(PetscViewerDrawGetDrawLG(v, c, &lg));
357:     PetscCall(PetscDrawLGReset(lg));
358:     PetscCall(PetscDrawLGSetDimension(lg, 1));
359:     PetscCall(PetscDrawLGSetColors(lg, colors));
360:     if (format == PETSC_VIEWER_DRAW_LG_XRANGE) {
361:       PetscCall(PetscDrawLGGetAxis(lg, &axis));
362:       PetscCall(PetscDrawAxisGetLimits(axis, &xmin, &xmax, NULL, NULL));
363:       h = (xmax - xmin) / n;
364:       for (i = 0; i < n; i++) xx[i] = i * h + 0.5 * h; /* cell center */
365:     } else {
366:       for (i = 0; i < n; i++) xx[i] = (PetscReal)i;
367:     }
368:     for (i = 0; i < n; i++) yy[i] = PetscRealPart(xv[c + i * bs]);

370:     PetscCall(PetscDrawLGAddPoints(lg, n, &xx, &yy));
371:     PetscCall(PetscDrawLGDraw(lg));
372:     PetscCall(PetscDrawLGSave(lg));
373:   }
374:   PetscCall(VecRestoreArrayRead(xin, &xv));
375:   PetscCall(PetscFree2(xx, yy));
376:   PetscFunctionReturn(PETSC_SUCCESS);
377: }

379: static PetscErrorCode VecView_Seq_Draw(Vec xin, PetscViewer v)
380: {
381:   PetscDraw draw;
382:   PetscBool isnull;

384:   PetscFunctionBegin;
385:   PetscCall(PetscViewerDrawGetDraw(v, 0, &draw));
386:   PetscCall(PetscDrawIsNull(draw, &isnull));
387:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);

389:   PetscCall(VecView_Seq_Draw_LG(xin, v));
390:   PetscFunctionReturn(PETSC_SUCCESS);
391: }

393: static PetscErrorCode VecView_Seq_Binary(Vec xin, PetscViewer viewer)
394: {
395:   return VecView_Binary(xin, viewer);
396: }

398: #if PetscDefined(HAVE_MATLAB)
399: #include <petscmatlab.h>
400:   #include <mat.h> /* MATLAB include file */
401: PetscErrorCode VecView_Seq_Matlab(Vec vec, PetscViewer viewer)
402: {
403:   PetscInt           n;
404:   const PetscScalar *array;

406:   PetscFunctionBegin;
407:   PetscCall(VecGetLocalSize(vec, &n));
408:   PetscCall(PetscObjectName((PetscObject)vec));
409:   PetscCall(VecGetArrayRead(vec, &array));
410:   PetscCall(PetscViewerMatlabPutArray(viewer, n, 1, array, ((PetscObject)vec)->name));
411:   PetscCall(VecRestoreArrayRead(vec, &array));
412:   PetscFunctionReturn(PETSC_SUCCESS);
413: }
414: #endif

416: PetscErrorCode VecView_Seq(Vec xin, PetscViewer viewer)
417: {
418:   PetscBool isdraw, isascii, issocket, isbinary;
419: #if PetscDefined(HAVE_MATLAB)
420:   PetscBool ismatlab;
421: #endif
422: #if PetscDefined(HAVE_HDF5)
423:   PetscBool ishdf5;
424: #endif
425:   PetscBool isglvis;
426: #if PetscDefined(HAVE_ADIOS)
427:   PetscBool isadios;
428: #endif

430:   PetscFunctionBegin;
431:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
432:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
433:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSOCKET, &issocket));
434:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
435: #if PetscDefined(HAVE_HDF5)
436:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
437: #endif
438: #if PetscDefined(HAVE_MATLAB)
439:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERMATLAB, &ismatlab));
440: #endif
441:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
442: #if PetscDefined(HAVE_ADIOS)
443:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERADIOS, &isadios));
444: #endif

446:   if (isdraw) {
447:     PetscCall(VecView_Seq_Draw(xin, viewer));
448:   } else if (isascii) {
449:     PetscCall(VecView_Seq_ASCII(xin, viewer));
450:   } else if (isbinary) {
451:     PetscCall(VecView_Seq_Binary(xin, viewer));
452: #if PetscDefined(HAVE_HDF5)
453:   } else if (ishdf5) {
454:     PetscCall(VecView_MPI_HDF5(xin, viewer)); /* Reusing VecView_MPI_HDF5 ... don't want code duplication*/
455: #endif
456: #if PetscDefined(HAVE_ADIOS)
457:   } else if (isadios) {
458:     PetscCall(VecView_MPI_ADIOS(xin, viewer)); /* Reusing VecView_MPI_ADIOS ... don't want code duplication*/
459: #endif
460: #if PetscDefined(HAVE_MATLAB)
461:   } else if (ismatlab) {
462:     PetscCall(VecView_Seq_Matlab(xin, viewer));
463: #endif
464:   } else if (isglvis) PetscCall(VecView_GLVis(xin, viewer));
465:   PetscFunctionReturn(PETSC_SUCCESS);
466: }

468: PetscErrorCode VecGetValues_Seq(Vec xin, PetscInt ni, const PetscInt ix[], PetscScalar y[])
469: {
470:   const PetscBool    ignorenegidx = xin->stash.ignorenegidx;
471:   const PetscScalar *xx;

473:   PetscFunctionBegin;
474:   PetscCall(VecGetArrayRead(xin, &xx));
475:   for (PetscInt i = 0; i < ni; ++i) {
476:     if (ignorenegidx && (ix[i] < 0)) continue;
477:     if (PetscDefined(USE_DEBUG)) {
478:       PetscCheck(ix[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Out of range index value %" PetscInt_FMT " cannot be negative", ix[i]);
479:       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);
480:     }
481:     y[i] = xx[ix[i]];
482:   }
483:   PetscCall(VecRestoreArrayRead(xin, &xx));
484:   PetscFunctionReturn(PETSC_SUCCESS);
485: }

487: PetscErrorCode VecSetValues_Seq(Vec xin, PetscInt ni, const PetscInt ix[], const PetscScalar y[], InsertMode m)
488: {
489:   const PetscBool ignorenegidx = xin->stash.ignorenegidx;
490:   PetscScalar    *xx;

492:   PetscFunctionBegin;
493:   // call to getarray (not e.g. getarraywrite() if m is INSERT_VALUES) is deliberate! If this
494:   // is secretly a VECSEQCUDA it may have values currently on the device, in which case --
495:   // unless we are replacing the entire array -- we need to copy them up
496:   PetscCall(VecGetArray(xin, &xx));
497:   for (PetscInt i = 0; i < ni; i++) {
498:     if (ignorenegidx && (ix[i] < 0)) continue;
499:     PetscScalar yv = y ? y[i] : 0.0;
500:     if (PetscDefined(USE_DEBUG)) {
501:       PetscCheck(ix[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Out of range index value %" PetscInt_FMT " cannot be negative", ix[i]);
502:       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);
503:     }
504:     if (m == INSERT_VALUES) {
505:       xx[ix[i]] = yv;
506:     } else {
507:       xx[ix[i]] += yv;
508:     }
509:   }
510:   PetscCall(VecRestoreArray(xin, &xx));
511:   PetscFunctionReturn(PETSC_SUCCESS);
512: }

514: PetscErrorCode VecSetValuesBlocked_Seq(Vec xin, PetscInt ni, const PetscInt ix[], const PetscScalar yin[], InsertMode m)
515: {
516:   PetscScalar *xx;
517:   PetscInt     bs;

519:   /* For optimization could treat bs = 2, 3, 4, 5 as special cases with loop unrolling */
520:   PetscFunctionBegin;
521:   PetscCall(VecGetBlockSize(xin, &bs));
522:   PetscCall(VecGetArray(xin, &xx));
523:   for (PetscInt i = 0; i < ni; ++i, yin += bs) {
524:     const PetscInt start = bs * ix[i];

526:     if (start < 0) continue;
527:     PetscCheck(start < xin->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Out of range index value %" PetscInt_FMT ", should be less than %" PetscInt_FMT, start, xin->map->n);
528:     for (PetscInt j = 0; j < bs; j++) {
529:       if (m == INSERT_VALUES) {
530:         xx[start + j] = yin ? yin[j] : 0.0;
531:       } else {
532:         xx[start + j] += yin ? yin[j] : 0.0;
533:       }
534:     }
535:   }
536:   PetscCall(VecRestoreArray(xin, &xx));
537:   PetscFunctionReturn(PETSC_SUCCESS);
538: }

540: static PetscErrorCode VecResetPreallocationCOO_Seq(Vec x)
541: {
542:   Vec_Seq *vs = (Vec_Seq *)x->data;

544:   PetscFunctionBegin;
545:   if (vs) {
546:     PetscCall(PetscFree(vs->jmap1)); /* Destroy old stuff */
547:     PetscCall(PetscFree(vs->perm1));
548:   }
549:   PetscFunctionReturn(PETSC_SUCCESS);
550: }

552: PetscErrorCode VecSetPreallocationCOO_Seq(Vec x, PetscCount coo_n, const PetscInt coo_i[])
553: {
554:   PetscInt    m, *i;
555:   PetscCount  k, nneg;
556:   PetscCount *perm1, *jmap1;
557:   Vec_Seq    *vs = (Vec_Seq *)x->data;

559:   PetscFunctionBegin;
560:   PetscCall(VecResetPreallocationCOO_Seq(x)); /* Destroy old stuff */
561:   PetscCall(PetscMalloc1(coo_n, &i));
562:   PetscCall(PetscArraycpy(i, coo_i, coo_n)); /* Make a copy since we'll modify it */
563:   PetscCall(PetscMalloc1(coo_n, &perm1));
564:   for (k = 0; k < coo_n; k++) perm1[k] = k;
565:   PetscCall(PetscSortIntWithCountArray(coo_n, i, perm1));
566:   for (k = 0; k < coo_n; k++) {
567:     if (i[k] >= 0) break;
568:   } /* Advance k to the first entry with a non-negative index */
569:   nneg = k;

571:   PetscCall(VecGetLocalSize(x, &m));
572:   PetscCheck(!nneg || x->stash.ignorenegidx, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Found a negative index in VecSetPreallocateCOO() but VEC_IGNORE_NEGATIVE_INDICES was not set");
573:   PetscCheck(!coo_n || i[coo_n - 1] < m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Found index (%" PetscInt_FMT ") greater than the size of the vector (%" PetscInt_FMT ") in VecSetPreallocateCOO()", i[coo_n - 1], m);

575:   PetscCall(PetscCalloc1(m + 1, &jmap1));
576:   for (; k < coo_n; k++) jmap1[i[k] + 1]++;         /* Count repeats of each entry */
577:   for (k = 0; k < m; k++) jmap1[k + 1] += jmap1[k]; /* Transform jmap[] to CSR-like data structure */
578:   PetscCall(PetscFree(i));

580:   if (nneg) { /* Discard leading negative indices */
581:     PetscCount *perm1_new;
582:     PetscCall(PetscMalloc1(coo_n - nneg, &perm1_new));
583:     PetscCall(PetscArraycpy(perm1_new, perm1 + nneg, coo_n - nneg));
584:     PetscCall(PetscFree(perm1));
585:     perm1 = perm1_new;
586:   }

588:   /* Record COO fields */
589:   vs->coo_n = coo_n;
590:   vs->tot1  = coo_n - nneg;
591:   vs->jmap1 = jmap1; /* [m+1] */
592:   vs->perm1 = perm1; /* [tot] */
593:   PetscFunctionReturn(PETSC_SUCCESS);
594: }

596: PetscErrorCode VecSetValuesCOO_Seq(Vec x, const PetscScalar coo_v[], InsertMode imode)
597: {
598:   Vec_Seq          *vs    = (Vec_Seq *)x->data;
599:   const PetscCount *perm1 = vs->perm1, *jmap1 = vs->jmap1;
600:   PetscScalar      *xv;
601:   PetscInt          m;

603:   PetscFunctionBegin;
604:   PetscCall(VecGetLocalSize(x, &m));
605:   PetscCall(VecGetArray(x, &xv));
606:   for (PetscInt i = 0; i < m; i++) {
607:     PetscScalar sum = 0.0;
608:     for (PetscCount j = jmap1[i]; j < jmap1[i + 1]; j++) sum += coo_v[perm1[j]];
609:     xv[i] = (imode == INSERT_VALUES ? 0.0 : xv[i]) + sum;
610:   }
611:   PetscCall(VecRestoreArray(x, &xv));
612:   PetscFunctionReturn(PETSC_SUCCESS);
613: }

615: PetscErrorCode VecDestroy_Seq(Vec v)
616: {
617:   Vec_Seq *vs = (Vec_Seq *)v->data;

619:   PetscFunctionBegin;
620:   PetscCall(PetscLogObjectState((PetscObject)v, "Length=%" PetscInt_FMT, v->map->n));
621:   if (vs) PetscCall(PetscShmgetDeallocateArray((void **)&vs->array_allocated));
622:   PetscCall(VecResetPreallocationCOO_Seq(v));
623:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscMatlabEnginePut_C", NULL));
624:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscMatlabEngineGet_C", NULL));
625:   PetscCall(PetscFree(v->data));
626:   PetscFunctionReturn(PETSC_SUCCESS);
627: }

629: PetscErrorCode VecSetOption_Seq(Vec v, VecOption op, PetscBool flag)
630: {
631:   PetscFunctionBegin;
632:   if (op == VEC_IGNORE_NEGATIVE_INDICES) v->stash.ignorenegidx = flag;
633:   PetscFunctionReturn(PETSC_SUCCESS);
634: }

636: // duplicate w to v. v is half-baked, potentially already with arrays allocated.
637: static PetscErrorCode VecDuplicate_Seq_Private(Vec w, Vec v)
638: {
639:   PetscFunctionBegin;
640:   PetscCall(VecSetType(v, ((PetscObject)w)->type_name));
641:   PetscCall(PetscObjectListDuplicate(((PetscObject)w)->olist, &((PetscObject)v)->olist));
642:   PetscCall(PetscFunctionListDuplicate(((PetscObject)w)->qlist, &((PetscObject)v)->qlist));

644:   // Vec ops are not necessarily fully set by VecSetType(), e.g., see DMCreateGlobalVector_DA, so we copy w's to v
645:   v->ops[0] = w->ops[0];
646: #if PetscDefined(HAVE_DEVICE)
647:   v->boundtocpu        = w->boundtocpu;
648:   v->bindingpropagates = w->bindingpropagates;
649: #endif
650:   PetscFunctionReturn(PETSC_SUCCESS);
651: }

653: PetscErrorCode VecDuplicate_Seq(Vec win, Vec *V)
654: {
655:   PetscFunctionBegin;
656:   PetscCall(VecCreateWithLayout_Private(win->map, V));
657:   PetscCall(VecDuplicate_Seq_Private(win, *V));
658:   PetscFunctionReturn(PETSC_SUCCESS);
659: }

661: PetscErrorCode VecReplaceArray_Default_GEMV_Error(Vec v, const PetscScalar *a)
662: {
663:   PetscFunctionBegin;
664:   PetscCheck(PETSC_FALSE, PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "VecReplaceArray() is not supported on the first Vec obtained from VecDuplicateVecs(). \
665: You could either 1) use -vec_mdot_use_gemv 0 -vec_maxpy_use_gemv 0 to turn off an optimization to allow your current code to work or 2) use VecDuplicate() to duplicate the vector.");
666:   (void)a;
667:   PetscFunctionReturn(PETSC_SUCCESS);
668: }

670: static PetscErrorCode VecDuplicateVecs_Seq_GEMV(Vec w, PetscInt m, Vec *V[])
671: {
672:   PetscScalar *array;
673:   PetscInt64   lda; // use 64-bit as we will do "m * lda"

675:   PetscFunctionBegin;
676:   PetscCall(PetscMalloc1(m, V));
677:   VecGetLocalSizeAligned(w, 64, &lda); // get in lda the 64-bytes aligned local size
678:   PetscCall(PetscCalloc1(m * lda, &array));
679:   for (PetscInt i = 0; i < m; i++) {
680:     Vec v;
681:     PetscCall(VecCreateSeqWithLayoutAndArray_Private(w->map, PetscSafePointerPlusOffset(array, i * lda), &v));
682:     PetscCall(VecDuplicate_Seq_Private(w, v));
683:     (*V)[i] = v;
684:   }
685:   // so when the first vector is destroyed it will destroy the array
686:   if (m) ((Vec_Seq *)(*V)[0]->data)->array_allocated = array;
687:   // disable replacearray of the first vector, as freeing its memory also frees others in the group.
688:   // But replacearray of others is ok, as they don't own their array.
689:   if (m > 1) (*V)[0]->ops->replacearray = VecReplaceArray_Default_GEMV_Error;
690:   PetscFunctionReturn(PETSC_SUCCESS);
691: }

693: static struct _VecOps DvOps = {
694:   PetscDesignatedInitializer(duplicate, VecDuplicate_Seq), /* 1 */
695:   PetscDesignatedInitializer(duplicatevecs, VecDuplicateVecs_Default),
696:   PetscDesignatedInitializer(destroyvecs, VecDestroyVecs_Default),
697:   PetscDesignatedInitializer(dot, VecDot_Seq),
698:   PetscDesignatedInitializer(mdot, VecMDot_Seq),
699:   PetscDesignatedInitializer(norm, VecNorm_Seq),
700:   PetscDesignatedInitializer(tdot, VecTDot_Seq),
701:   PetscDesignatedInitializer(mtdot, VecMTDot_Seq),
702:   PetscDesignatedInitializer(scale, VecScale_Seq),
703:   PetscDesignatedInitializer(copy, VecCopy_Seq), /* 10 */
704:   PetscDesignatedInitializer(set, VecSet_Seq),
705:   PetscDesignatedInitializer(swap, VecSwap_Seq),
706:   PetscDesignatedInitializer(axpy, VecAXPY_Seq),
707:   PetscDesignatedInitializer(axpby, VecAXPBY_Seq),
708:   PetscDesignatedInitializer(maxpy, VecMAXPY_Seq),
709:   PetscDesignatedInitializer(aypx, VecAYPX_Seq),
710:   PetscDesignatedInitializer(waxpy, VecWAXPY_Seq),
711:   PetscDesignatedInitializer(axpbypcz, VecAXPBYPCZ_Seq),
712:   PetscDesignatedInitializer(pointwisemult, VecPointwiseMult_Seq),
713:   PetscDesignatedInitializer(pointwisedivide, VecPointwiseDivide_Seq),
714:   PetscDesignatedInitializer(setvalues, VecSetValues_Seq), /* 20 */
715:   PetscDesignatedInitializer(assemblybegin, NULL),
716:   PetscDesignatedInitializer(assemblyend, NULL),
717:   PetscDesignatedInitializer(getarray, NULL),
718:   PetscDesignatedInitializer(getsize, VecGetSize_Seq),
719:   PetscDesignatedInitializer(getlocalsize, VecGetSize_Seq),
720:   PetscDesignatedInitializer(restorearray, NULL),
721:   PetscDesignatedInitializer(max, VecMax_Seq),
722:   PetscDesignatedInitializer(min, VecMin_Seq),
723:   PetscDesignatedInitializer(setrandom, VecSetRandom_Seq),
724:   PetscDesignatedInitializer(setoption, VecSetOption_Seq), /* 30 */
725:   PetscDesignatedInitializer(setvaluesblocked, VecSetValuesBlocked_Seq),
726:   PetscDesignatedInitializer(destroy, VecDestroy_Seq),
727:   PetscDesignatedInitializer(view, VecView_Seq),
728:   PetscDesignatedInitializer(placearray, VecPlaceArray_Seq),
729:   PetscDesignatedInitializer(replacearray, VecReplaceArray_Seq),
730:   PetscDesignatedInitializer(dot_local, VecDot_Seq),
731:   PetscDesignatedInitializer(tdot_local, VecTDot_Seq),
732:   PetscDesignatedInitializer(norm_local, VecNorm_Seq),
733:   PetscDesignatedInitializer(mdot_local, VecMDot_Seq),
734:   PetscDesignatedInitializer(mtdot_local, VecMTDot_Seq), /* 40 */
735:   PetscDesignatedInitializer(load, VecLoad_Default),
736:   PetscDesignatedInitializer(reciprocal, VecReciprocal_Default),
737:   PetscDesignatedInitializer(conjugate, VecConjugate_Seq),
738:   PetscDesignatedInitializer(setlocaltoglobalmapping, NULL),
739:   PetscDesignatedInitializer(getlocaltoglobalmapping, NULL),
740:   PetscDesignatedInitializer(resetarray, VecResetArray_Seq),
741:   PetscDesignatedInitializer(setfromoptions, NULL),
742:   PetscDesignatedInitializer(maxpointwisedivide, VecMaxPointwiseDivide_Seq),
743:   PetscDesignatedInitializer(pointwisemax, VecPointwiseMax_Seq),
744:   PetscDesignatedInitializer(pointwisemaxabs, VecPointwiseMaxAbs_Seq),
745:   PetscDesignatedInitializer(pointwisemin, VecPointwiseMin_Seq),
746:   PetscDesignatedInitializer(getvalues, VecGetValues_Seq),
747:   PetscDesignatedInitializer(sqrt, NULL),
748:   PetscDesignatedInitializer(abs, NULL),
749:   PetscDesignatedInitializer(exp, NULL),
750:   PetscDesignatedInitializer(log, NULL),
751:   PetscDesignatedInitializer(shift, NULL),
752:   PetscDesignatedInitializer(create, NULL),
753:   PetscDesignatedInitializer(stridegather, VecStrideGather_Default),
754:   PetscDesignatedInitializer(stridescatter, VecStrideScatter_Default),
755:   PetscDesignatedInitializer(dotnorm2, NULL),
756:   PetscDesignatedInitializer(getsubvector, NULL),
757:   PetscDesignatedInitializer(restoresubvector, NULL),
758:   PetscDesignatedInitializer(getarrayread, NULL),
759:   PetscDesignatedInitializer(restorearrayread, NULL),
760:   PetscDesignatedInitializer(stridesubsetgather, VecStrideSubSetGather_Default),
761:   PetscDesignatedInitializer(stridesubsetscatter, VecStrideSubSetScatter_Default),
762:   PetscDesignatedInitializer(viewnative, VecView_Seq),
763:   PetscDesignatedInitializer(loadnative, NULL),
764:   PetscDesignatedInitializer(createlocalvector, NULL),
765:   PetscDesignatedInitializer(getlocalvector, NULL),
766:   PetscDesignatedInitializer(restorelocalvector, NULL),
767:   PetscDesignatedInitializer(getlocalvectorread, NULL),
768:   PetscDesignatedInitializer(restorelocalvectorread, NULL),
769:   PetscDesignatedInitializer(bindtocpu, NULL),
770:   PetscDesignatedInitializer(getarraywrite, NULL),
771:   PetscDesignatedInitializer(restorearraywrite, NULL),
772:   PetscDesignatedInitializer(getarrayandmemtype, NULL),
773:   PetscDesignatedInitializer(restorearrayandmemtype, NULL),
774:   PetscDesignatedInitializer(getarrayreadandmemtype, NULL),
775:   PetscDesignatedInitializer(restorearrayreadandmemtype, NULL),
776:   PetscDesignatedInitializer(getarraywriteandmemtype, NULL),
777:   PetscDesignatedInitializer(restorearraywriteandmemtype, NULL),
778:   PetscDesignatedInitializer(concatenate, NULL),
779:   PetscDesignatedInitializer(sum, NULL),
780:   PetscDesignatedInitializer(setpreallocationcoo, VecSetPreallocationCOO_Seq),
781:   PetscDesignatedInitializer(setvaluescoo, VecSetValuesCOO_Seq),
782:   PetscDesignatedInitializer(errorwnorm, NULL),
783:   PetscDesignatedInitializer(maxpby, NULL),
784:   PetscDesignatedInitializer(setstdbasis, NULL),
785: };

787: /*
788:   Create a VECSEQ with the given layout and array

790:   Input Parameter:
791: + map   - the layout
792: - array - the array on host

794:   Output Parameter:
795: . V  - The vector object
796: */
797: PetscErrorCode VecCreateSeqWithLayoutAndArray_Private(PetscLayout map, const PetscScalar array[], Vec *V)
798: {
799:   PetscMPIInt size;

801:   PetscFunctionBegin;
802:   PetscCall(VecCreateWithLayout_Private(map, V));
803:   PetscCallMPI(MPI_Comm_size(map->comm, &size));
804:   PetscCheck(size == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot create VECSEQ on more than one process");
805:   PetscCall(VecCreate_Seq_Private(*V, array));
806:   PetscFunctionReturn(PETSC_SUCCESS);
807: }

809: /*
810:       This is called by VecCreate_Seq() (i.e. VecCreateSeq()) and VecCreateSeqWithArray()
811: */
812: PetscErrorCode VecCreate_Seq_Private(Vec v, const PetscScalar array[])
813: {
814:   Vec_Seq  *s;
815:   PetscBool mdot_use_gemv  = PETSC_TRUE;
816:   PetscBool maxpy_use_gemv = PETSC_FALSE; // default is false as we saw bad performance with vendors' GEMV with tall skinny matrices.

818:   PetscFunctionBegin;
819:   PetscCall(PetscNew(&s));
820:   v->ops[0] = DvOps;

822:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-vec_mdot_use_gemv", &mdot_use_gemv, NULL));
823:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-vec_maxpy_use_gemv", &maxpy_use_gemv, NULL));

825:   // allocate multiple vectors together
826:   if (mdot_use_gemv || maxpy_use_gemv) v->ops[0].duplicatevecs = VecDuplicateVecs_Seq_GEMV;

828:   if (mdot_use_gemv) {
829:     v->ops[0].mdot        = VecMDot_Seq_GEMV;
830:     v->ops[0].mdot_local  = VecMDot_Seq_GEMV;
831:     v->ops[0].mtdot       = VecMTDot_Seq_GEMV;
832:     v->ops[0].mtdot_local = VecMTDot_Seq_GEMV;
833:   }
834:   if (maxpy_use_gemv) v->ops[0].maxpy = VecMAXPY_Seq_GEMV;

836:   v->data            = (void *)s;
837:   v->petscnative     = PETSC_TRUE;
838:   s->array           = (PetscScalar *)array;
839:   s->array_allocated = NULL;
840:   if (array) v->offloadmask = PETSC_OFFLOAD_CPU;

842:   PetscCall(PetscLayoutSetUp(v->map));
843:   PetscCall(PetscObjectChangeTypeName((PetscObject)v, VECSEQ));
844: #if PetscDefined(HAVE_MATLAB)
845:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscMatlabEnginePut_C", VecMatlabEnginePut_Default));
846:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscMatlabEngineGet_C", VecMatlabEngineGet_Default));
847: #endif
848:   PetscFunctionReturn(PETSC_SUCCESS);
849: }

851: /*@
852:   VecCreateSeqWithArray - Creates a standard,sequential array-style vector,
853:   where the user provides the array space to store the vector values.

855:   Collective

857:   Input Parameters:
858: + comm  - the communicator, should be `PETSC_COMM_SELF`
859: . bs    - the block size
860: . n     - the vector length
861: - array - memory where the vector elements are to be stored.

863:   Output Parameter:
864: . V - the vector

866:   Level: intermediate

868:   Notes:
869:   Use `VecDuplicate()` or `VecDuplicateVecs(`) to form additional vectors of the
870:   same type as an existing vector.

872:   If the user-provided array is` NULL`, then `VecPlaceArray()` can be used
873:   at a later stage to SET the array for storing the vector values.

875:   PETSc does NOT free the array when the vector is destroyed via `VecDestroy()`.
876:   The user should not free the array until the vector is destroyed.

878: .seealso: `VecCreateSeqWithArrayAndMemType()`, `VecCreateMPIWithArray()`, `VecCreate()`, `VecDuplicate()`, `VecDuplicateVecs()`,
879:           `VecCreateGhost()`, `VecCreateSeq()`, `VecPlaceArray()`
880: @*/
881: PetscErrorCode VecCreateSeqWithArray(MPI_Comm comm, PetscInt bs, PetscInt n, const PetscScalar array[], Vec *V)
882: {
883:   PetscMPIInt size;

885:   PetscFunctionBegin;
886:   PetscCall(VecCreate(comm, V));
887:   PetscCall(VecSetSizes(*V, n, n));
888:   PetscCall(VecSetBlockSize(*V, bs));
889:   PetscCallMPI(MPI_Comm_size(comm, &size));
890:   PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot create VECSEQ on more than one process");
891:   PetscCall(VecCreate_Seq_Private(*V, array));
892:   PetscFunctionReturn(PETSC_SUCCESS);
893: }