Actual source code: data_bucket.c

  1: #include "../src/dm/impls/swarm/data_bucket.h"

  3: /* string helpers */
  4: PetscErrorCode DMSwarmDataFieldStringInList(const char name[], const PetscInt N, const DMSwarmDataField gfield[], PetscBool *val)
  5: {
  6:   PetscFunctionBegin;
  7:   *val = PETSC_FALSE;
  8:   for (PetscInt i = 0; i < N; ++i) {
  9:     PetscBool flg;
 10:     PetscCall(PetscStrcmp(name, gfield[i]->name, &flg));
 11:     if (flg) {
 12:       *val = PETSC_TRUE;
 13:       PetscFunctionReturn(PETSC_SUCCESS);
 14:     }
 15:   }
 16:   PetscFunctionReturn(PETSC_SUCCESS);
 17: }

 19: PetscErrorCode DMSwarmDataFieldStringFindInList(const char name[], const PetscInt N, const DMSwarmDataField gfield[], PetscInt *index)
 20: {
 21:   PetscFunctionBegin;
 22:   *index = -1;
 23:   for (PetscInt i = 0; i < N; ++i) {
 24:     PetscBool flg;
 25:     PetscCall(PetscStrcmp(name, gfield[i]->name, &flg));
 26:     if (flg) {
 27:       *index = i;
 28:       PetscFunctionReturn(PETSC_SUCCESS);
 29:     }
 30:   }
 31:   PetscFunctionReturn(PETSC_SUCCESS);
 32: }

 34: PetscErrorCode DMSwarmDataFieldCreate(const char registration_function[], const char name[], const size_t size, const PetscInt L, DMSwarmDataField *DF)
 35: {
 36:   DMSwarmDataField df;

 38:   PetscFunctionBegin;
 39:   PetscCall(PetscNew(&df));
 40:   PetscCall(PetscStrallocpy(registration_function, &df->registration_function));
 41:   PetscCall(PetscStrallocpy(name, &df->name));
 42:   df->atomic_size = size;
 43:   df->L           = L;
 44:   df->bs          = 1;
 45:   /* allocate something so we don't have to reallocate */
 46:   PetscCall(PetscMalloc(size * L, &df->data));
 47:   PetscCall(PetscMemzero(df->data, size * L));
 48:   *DF = df;
 49:   PetscFunctionReturn(PETSC_SUCCESS);
 50: }

 52: PetscErrorCode DMSwarmDataFieldDestroy(DMSwarmDataField *DF)
 53: {
 54:   DMSwarmDataField df = *DF;

 56:   PetscFunctionBegin;
 57:   PetscCall(PetscFree(df->registration_function));
 58:   PetscCall(PetscFree(df->name));
 59:   PetscCall(PetscFree(df->data));
 60:   PetscCall(PetscFree(df));
 61:   *DF = NULL;
 62:   PetscFunctionReturn(PETSC_SUCCESS);
 63: }

 65: /* data bucket */
 66: PetscErrorCode DMSwarmDataBucketCreate(DMSwarmDataBucket *DB)
 67: {
 68:   DMSwarmDataBucket db;

 70:   PetscFunctionBegin;
 71:   PetscCall(PetscNew(&db));

 73:   db->finalised = PETSC_FALSE;
 74:   /* create empty spaces for fields */
 75:   db->L         = -1;
 76:   db->buffer    = 1;
 77:   db->allocated = 1;
 78:   db->nfields   = 0;
 79:   PetscCall(PetscMalloc1(1, &db->field));
 80:   *DB = db;
 81:   PetscFunctionReturn(PETSC_SUCCESS);
 82: }

 84: PetscErrorCode DMSwarmDataBucketDestroy(DMSwarmDataBucket *DB)
 85: {
 86:   DMSwarmDataBucket db = *DB;
 87:   PetscInt          f;

 89:   PetscFunctionBegin;
 90:   /* release fields */
 91:   for (f = 0; f < db->nfields; ++f) PetscCall(DMSwarmDataFieldDestroy(&db->field[f]));
 92:   /* this will catch the initially allocated objects in the event that no fields are registered */
 93:   if (db->field != NULL) PetscCall(PetscFree(db->field));
 94:   PetscCall(PetscFree(db));
 95:   *DB = NULL;
 96:   PetscFunctionReturn(PETSC_SUCCESS);
 97: }

 99: PetscErrorCode DMSwarmDataBucketQueryForActiveFields(DMSwarmDataBucket db, PetscBool *any_active_fields)
100: {
101:   PetscInt f;

103:   PetscFunctionBegin;
104:   *any_active_fields = PETSC_FALSE;
105:   for (f = 0; f < db->nfields; ++f) {
106:     if (db->field[f]->active) {
107:       *any_active_fields = PETSC_TRUE;
108:       PetscFunctionReturn(PETSC_SUCCESS);
109:     }
110:   }
111:   PetscFunctionReturn(PETSC_SUCCESS);
112: }

114: PetscErrorCode DMSwarmDataBucketRegisterField(DMSwarmDataBucket db, const char registration_function[], const char field_name[], size_t atomic_size, DMSwarmDataField *_gfield)
115: {
116:   PetscBool        val;
117:   DMSwarmDataField fp;

119:   PetscFunctionBegin;
120:   /* check we haven't finalised the registration of fields */
121:   /*
122:    if (db->finalised==PETSC_TRUE) {
123:    printf("ERROR: DMSwarmDataBucketFinalize() has been called. Cannot register more fields\n");
124:    ERROR();
125:    }
126:   */
127:   /* check for repeated name */
128:   PetscCall(DMSwarmDataFieldStringInList(field_name, db->nfields, (const DMSwarmDataField *)db->field, &val));
129:   PetscCheck(val != PETSC_TRUE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field %s already exists. Cannot add same field twice", field_name);
130:   /* create new space for data */
131:   PetscCall(PetscRealloc(sizeof(DMSwarmDataField) * (db->nfields + 1), &db->field));
132:   /* add field */
133:   PetscCall(DMSwarmDataFieldCreate(registration_function, field_name, atomic_size, db->allocated, &fp));
134:   db->field[db->nfields] = fp;
135:   db->nfields++;
136:   if (_gfield != NULL) *_gfield = fp;
137:   PetscFunctionReturn(PETSC_SUCCESS);
138: }

140: /*
141:  #define DMSwarmDataBucketRegisterField(db,name,size,k) {\
142:  char *location;\
143:  asprintf(&location,"Registered by %s() at line %d within file %s", __FUNCTION__, __LINE__, __FILE__);\
144:  _DMSwarmDataBucketRegisterField( (db), location, (name), (size), (k));\
145:  ierr = PetscFree(location);\
146:  }
147:  */

149: /*@C
150:   DMSwarmDataBucketGetDMSwarmDataFieldIdByName - Return the index of a `DMSwarmDataField` within a `DMSwarmDataBucket` given its name.

152:   Not Collective

154:   Input Parameters:
155: + db   - the `DMSwarmDataBucket`
156: - name - the field name

158:   Output Parameter:
159: . idx - the index of the field within the bucket

161:   Level: developer

163:   Note:
164:   Errors if no field with the given name is registered; use `DMSwarmDataBucketQueryDMSwarmDataFieldByName()` first when the name may be absent.

166: .seealso: `DMSwarmDataBucket`, `DMSwarmDataField`, `DMSwarmDataBucketGetDMSwarmDataFieldByName()`, `DMSwarmDataBucketQueryDMSwarmDataFieldByName()`
167: @*/
168: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldIdByName(DMSwarmDataBucket db, const char name[], PetscInt *idx)
169: {
170:   PetscBool found;

172:   PetscFunctionBegin;
173:   *idx = -1;
174:   PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, &found));
175:   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot find DMSwarmDataField with name %s", name);
176:   PetscCall(DMSwarmDataFieldStringFindInList(name, db->nfields, (const DMSwarmDataField *)db->field, idx));
177:   PetscFunctionReturn(PETSC_SUCCESS);
178: }

180: /*@C
181:   DMSwarmDataBucketGetDMSwarmDataFieldByName - Return the `DMSwarmDataField` handle registered in a `DMSwarmDataBucket` under a given name.

183:   Not Collective

185:   Input Parameters:
186: + db   - the `DMSwarmDataBucket`
187: - name - the field name

189:   Output Parameter:
190: . gfield - the `DMSwarmDataField` handle

192:   Level: developer

194:   Note:
195:   Errors if no field with the given name is registered; use `DMSwarmDataBucketQueryDMSwarmDataFieldByName()` first when the name may be absent.

197: .seealso: `DMSwarmDataBucket`, `DMSwarmDataField`, `DMSwarmDataBucketGetDMSwarmDataFieldIdByName()`, `DMSwarmDataBucketQueryDMSwarmDataFieldByName()`
198: @*/
199: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldByName(DMSwarmDataBucket db, const char name[], DMSwarmDataField *gfield)
200: {
201:   PetscInt  idx;
202:   PetscBool found;

204:   PetscFunctionBegin;
205:   PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, &found));
206:   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot find DMSwarmDataField with name %s", name);
207:   PetscCall(DMSwarmDataFieldStringFindInList(name, db->nfields, (const DMSwarmDataField *)db->field, &idx));
208:   *gfield = db->field[idx];
209:   PetscFunctionReturn(PETSC_SUCCESS);
210: }

212: /*@C
213:   DMSwarmDataBucketQueryDMSwarmDataFieldByName - Test whether a `DMSwarmDataBucket` contains a `DMSwarmDataField` with the given name.

215:   Not Collective

217:   Input Parameters:
218: + db   - the `DMSwarmDataBucket`
219: - name - the field name to look up

221:   Output Parameter:
222: . found - `PETSC_TRUE` if a field with the given name is registered, otherwise `PETSC_FALSE`

224:   Level: developer

226: .seealso: `DMSwarmDataBucket`, `DMSwarmDataField`, `DMSwarmDataBucketGetDMSwarmDataFieldByName()`, `DMSwarmDataBucketGetDMSwarmDataFieldIdByName()`
227: @*/
228: PetscErrorCode DMSwarmDataBucketQueryDMSwarmDataFieldByName(DMSwarmDataBucket db, const char name[], PetscBool *found)
229: {
230:   PetscFunctionBegin;
231:   *found = PETSC_FALSE;
232:   PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, found));
233:   PetscFunctionReturn(PETSC_SUCCESS);
234: }

236: PetscErrorCode DMSwarmDataBucketFinalize(DMSwarmDataBucket db)
237: {
238:   PetscFunctionBegin;
239:   db->finalised = PETSC_TRUE;
240:   PetscFunctionReturn(PETSC_SUCCESS);
241: }

243: PetscErrorCode DMSwarmDataFieldGetNumEntries(DMSwarmDataField df, PetscInt *sum)
244: {
245:   PetscFunctionBegin;
246:   *sum = df->L;
247:   PetscFunctionReturn(PETSC_SUCCESS);
248: }

250: PetscErrorCode DMSwarmDataFieldSetBlockSize(DMSwarmDataField df, PetscInt blocksize)
251: {
252:   PetscFunctionBegin;
253:   df->bs = blocksize;
254:   PetscFunctionReturn(PETSC_SUCCESS);
255: }

257: PetscErrorCode DMSwarmDataFieldSetSize(DMSwarmDataField df, const PetscInt new_L)
258: {
259:   PetscFunctionBegin;
260:   PetscCheck(new_L >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot set size of DMSwarmDataField to be < 0");
261:   if (new_L == df->L) PetscFunctionReturn(PETSC_SUCCESS);
262:   if (new_L > df->L) {
263:     PetscCall(PetscRealloc(df->atomic_size * (new_L), &df->data));
264:     /* init new contents */
265:     PetscCall(PetscMemzero(((char *)df->data) + df->L * df->atomic_size, (new_L - df->L) * df->atomic_size));
266:   } else {
267:     /* reallocate pointer list, add +1 in case new_L = 0 */
268:     PetscCall(PetscRealloc(df->atomic_size * (new_L + 1), &df->data));
269:   }
270:   df->L = new_L;
271:   PetscFunctionReturn(PETSC_SUCCESS);
272: }

274: PetscErrorCode DMSwarmDataFieldZeroBlock(DMSwarmDataField df, const PetscInt start, const PetscInt end)
275: {
276:   PetscFunctionBegin;
277:   PetscCheck(start <= end, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") > end(%" PetscInt_FMT ")", start, end);
278:   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") < 0", start);
279:   PetscCheck(end <= df->L, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if end(%" PetscInt_FMT ") >= array size(%" PetscInt_FMT ")", end, df->L);
280:   PetscCall(PetscMemzero(((char *)df->data) + start * df->atomic_size, (end - start) * df->atomic_size));
281:   PetscFunctionReturn(PETSC_SUCCESS);
282: }

284: /*
285:  A negative buffer value will simply be ignored and the old buffer value will be used.
286:  */
287: PetscErrorCode DMSwarmDataBucketSetSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
288: {
289:   PetscInt  current_allocated, current_used, new_used, new_unused, new_buffer, new_allocated, f, end;
290:   PetscBool any_active_fields;

292:   PetscFunctionBegin;
293:   PetscCheck(db->finalised != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "You must call DMSwarmDataBucketFinalize() before DMSwarmDataBucketSetSizes()");
294:   PetscCall(DMSwarmDataBucketQueryForActiveFields(db, &any_active_fields));
295:   PetscCheck(!any_active_fields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot safely re-size as at least one DMSwarmDataField is currently being accessed");

297:   current_allocated = db->allocated;
298:   current_used      = PetscMax(db->L, 0);
299:   new_used          = L;
300:   new_unused        = current_allocated - new_used;
301:   new_buffer        = db->buffer;
302:   if (buffer >= 0) { /* update the buffer value */
303:     new_buffer = buffer;
304:   }
305:   new_allocated = new_used + new_buffer;
306:   /* action */
307:   if (new_allocated > current_allocated) {
308:     /* increase size to new_used + new_buffer and zero new space */
309:     for (f = 0; f < db->nfields; f++) {
310:       PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
311:       PetscCall(DMSwarmDataFieldZeroBlock(db->field[f], current_allocated, new_allocated));
312:     }
313:     db->L         = new_used;
314:     db->buffer    = new_buffer;
315:     db->allocated = new_used + new_buffer;
316:   } else {
317:     if (new_unused > 2 * new_buffer) {
318:       /* shrink array to new_used + new_buffer */
319:       for (f = 0; f < db->nfields; ++f) PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
320:       db->L         = new_used;
321:       db->buffer    = new_buffer;
322:       db->allocated = new_used + new_buffer;
323:     } else {
324:       db->L      = new_used;
325:       db->buffer = new_buffer;
326:     }
327:   }
328:   /* if we shrunk, zero old entries from new_used to current_used or end of array */
329:   end = PetscMin(current_used, new_allocated);
330:   if (end > new_used) {
331:     for (f = 0; f < db->nfields; ++f) {
332:       DMSwarmDataField field = db->field[f];
333:       PetscCall(DMSwarmDataFieldZeroBlock(field, new_used, end));
334:     }
335:   }
336:   PetscFunctionReturn(PETSC_SUCCESS);
337: }

339: PetscErrorCode DMSwarmDataBucketSetInitialSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
340: {
341:   PetscInt f;

343:   PetscFunctionBegin;
344:   PetscCall(DMSwarmDataBucketSetSizes(db, L, buffer));
345:   for (f = 0; f < db->nfields; ++f) {
346:     DMSwarmDataField field = db->field[f];
347:     PetscCall(DMSwarmDataFieldZeroBlock(field, 0, db->allocated));
348:   }
349:   PetscFunctionReturn(PETSC_SUCCESS);
350: }

352: PetscErrorCode DMSwarmDataBucketGetSizes(DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
353: {
354:   PetscFunctionBegin;
355:   if (L) *L = db->L;
356:   if (buffer) *buffer = db->buffer;
357:   if (allocated) *allocated = db->allocated;
358:   PetscFunctionReturn(PETSC_SUCCESS);
359: }

361: PetscErrorCode DMSwarmDataBucketGetGlobalSizes(MPI_Comm comm, DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
362: {
363:   PetscFunctionBegin;
364:   if (L) PetscCallMPI(MPIU_Allreduce(&db->L, L, 1, MPIU_INT, MPI_SUM, comm));
365:   if (buffer) PetscCallMPI(MPIU_Allreduce(&db->buffer, buffer, 1, MPIU_INT, MPI_SUM, comm));
366:   if (allocated) PetscCallMPI(MPIU_Allreduce(&db->allocated, allocated, 1, MPIU_INT, MPI_SUM, comm));
367:   PetscFunctionReturn(PETSC_SUCCESS);
368: }

370: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFields(DMSwarmDataBucket db, PetscInt *L, DMSwarmDataField *fields[])
371: {
372:   PetscFunctionBegin;
373:   if (L) *L = db->nfields;
374:   if (fields) *fields = db->field;
375:   PetscFunctionReturn(PETSC_SUCCESS);
376: }

378: PetscErrorCode DMSwarmDataFieldGetAccess(const DMSwarmDataField gfield)
379: {
380:   PetscFunctionBegin;
381:   PetscCheck(!gfield->active, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is already active. You must call DMSwarmDataFieldRestoreAccess()", gfield->name);
382:   gfield->active = PETSC_TRUE;
383:   PetscFunctionReturn(PETSC_SUCCESS);
384: }

386: PetscErrorCode DMSwarmDataFieldAccessPoint(const DMSwarmDataField gfield, const PetscInt pid, void **ctx_p)
387: {
388:   PetscFunctionBegin;
389:   *ctx_p = NULL;
390: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
391:   /* debug mode */
392:   /* check point is valid */
393:   PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
394:   PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
395:   PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess() before point data can be retrivied", gfield->name);
396: #endif
397:   *ctx_p = DMSWARM_DATAFIELD_point_access(gfield->data, pid, gfield->atomic_size);
398:   PetscFunctionReturn(PETSC_SUCCESS);
399: }

401: PetscErrorCode DMSwarmDataFieldAccessPointOffset(const DMSwarmDataField gfield, const size_t offset, const PetscInt pid, void **ctx_p)
402: {
403:   PetscFunctionBegin;
404: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
405:   /* debug mode */
406:   /* check point is valid */
407:   /* PetscCheck(offset >= 0,PETSC_COMM_SELF,PETSC_ERR_USER,"offset must be >= 0");*/
408:   /* Note compiler realizes this can never happen with an unsigned PetscInt */
409:   PetscCheck(offset < gfield->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "offset must be < %zu", gfield->atomic_size);
410:   /* check point is valid */
411:   PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
412:   PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
413:   PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess() before point data can be retrivied", gfield->name);
414: #endif
415:   *ctx_p = DMSWARM_DATAFIELD_point_access_offset(gfield->data, pid, gfield->atomic_size, offset);
416:   PetscFunctionReturn(PETSC_SUCCESS);
417: }

419: PetscErrorCode DMSwarmDataFieldRestoreAccess(DMSwarmDataField gfield)
420: {
421:   PetscFunctionBegin;
422:   PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess()", gfield->name);
423:   gfield->active = PETSC_FALSE;
424:   PetscFunctionReturn(PETSC_SUCCESS);
425: }

427: PetscErrorCode DMSwarmDataFieldVerifyAccess(const DMSwarmDataField gfield, const size_t size)
428: {
429:   PetscFunctionBegin;
430: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
431:   PetscCheck(gfield->atomic_size == size, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" must be mapped to %zu bytes, your intended structure is %zu bytes in length.", gfield->name, gfield->atomic_size, size);
432: #endif
433:   PetscFunctionReturn(PETSC_SUCCESS);
434: }

436: PetscErrorCode DMSwarmDataFieldGetAtomicSize(const DMSwarmDataField gfield, size_t *size)
437: {
438:   PetscFunctionBegin;
439:   if (size) *size = gfield->atomic_size;
440:   PetscFunctionReturn(PETSC_SUCCESS);
441: }

443: /*@C
444:   DMSwarmDataFieldGetEntries - Return a pointer to the raw contiguous storage backing a `DMSwarmDataField`.

446:   Not Collective

448:   Input Parameter:
449: . gfield - the `DMSwarmDataField`

451:   Output Parameter:
452: . data - pointer to the raw entries; must be released with `DMSwarmDataFieldRestoreEntries()`

454:   Level: developer

456:   Note:
457:   The array has `L * bs` entries of `atomic_size` bytes, where `L` is the number of particles and `bs` is the block size of the field.

459: .seealso: `DMSwarmDataField`, `DMSwarmDataFieldRestoreEntries()`, `DMSwarmDataFieldGetNumEntries()`, `DMSwarmDataFieldGetAtomicSize()`
460: @*/
461: PetscErrorCode DMSwarmDataFieldGetEntries(const DMSwarmDataField gfield, void **data)
462: {
463:   PetscFunctionBegin;
464:   if (data) *data = gfield->data;
465:   PetscFunctionReturn(PETSC_SUCCESS);
466: }

468: /*@C
469:   DMSwarmDataFieldRestoreEntries - Release a pointer obtained from `DMSwarmDataFieldGetEntries()`, clearing the caller's handle to `NULL`.

471:   Not Collective

473:   Input Parameter:
474: . gfield - the `DMSwarmDataField`

476:   Output Parameter:
477: . data - pointer that will be set to `NULL`

479:   Level: developer

481: .seealso: `DMSwarmDataField`, `DMSwarmDataFieldGetEntries()`
482: @*/
483: PetscErrorCode DMSwarmDataFieldRestoreEntries(const DMSwarmDataField gfield, void **data)
484: {
485:   PetscFunctionBegin;
486:   if (data) *data = NULL;
487:   PetscFunctionReturn(PETSC_SUCCESS);
488: }

490: /* y = x */
491: PetscErrorCode DMSwarmDataBucketCopyPoint(const DMSwarmDataBucket xb, const PetscInt pid_x, const DMSwarmDataBucket yb, const PetscInt pid_y)
492: {
493:   PetscInt f;

495:   PetscFunctionBegin;
496:   for (f = 0; f < xb->nfields; ++f) {
497:     void *dest;
498:     void *src;

500:     PetscCall(DMSwarmDataFieldGetAccess(xb->field[f]));
501:     if (xb != yb) PetscCall(DMSwarmDataFieldGetAccess(yb->field[f]));
502:     PetscCall(DMSwarmDataFieldAccessPoint(xb->field[f], pid_x, &src));
503:     PetscCall(DMSwarmDataFieldAccessPoint(yb->field[f], pid_y, &dest));
504:     PetscCall(PetscMemcpy(dest, src, xb->field[f]->atomic_size));
505:     PetscCall(DMSwarmDataFieldRestoreAccess(xb->field[f]));
506:     if (xb != yb) PetscCall(DMSwarmDataFieldRestoreAccess(yb->field[f]));
507:   }
508:   PetscFunctionReturn(PETSC_SUCCESS);
509: }

511: PetscErrorCode DMSwarmDataBucketCreateFromSubset(DMSwarmDataBucket DBIn, const PetscInt N, const PetscInt list[], DMSwarmDataBucket *DB)
512: {
513:   PetscInt          nfields;
514:   DMSwarmDataField *fields;
515:   PetscInt          f, L, buffer, allocated, p;

517:   PetscFunctionBegin;
518:   PetscCall(DMSwarmDataBucketCreate(DB));
519:   /* copy contents of DBIn */
520:   PetscCall(DMSwarmDataBucketGetDMSwarmDataFields(DBIn, &nfields, &fields));
521:   PetscCall(DMSwarmDataBucketGetSizes(DBIn, &L, &buffer, &allocated));
522:   for (f = 0; f < nfields; ++f) PetscCall(DMSwarmDataBucketRegisterField(*DB, "DMSwarmDataBucketCreateFromSubset", fields[f]->name, fields[f]->atomic_size, NULL));
523:   PetscCall(DMSwarmDataBucketFinalize(*DB));
524:   PetscCall(DMSwarmDataBucketSetSizes(*DB, L, buffer));
525:   for (f = 0; f < nfields; ++f) {
526:     DMSwarmDataField gfield;

528:     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(*DB, fields[f]->name, &gfield));
529:     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, fields[f]->bs));
530:     gfield->petsc_type = fields[f]->petsc_type;
531:   }
532:   /* now copy the desired guys from DBIn => DB */
533:   for (p = 0; p < N; ++p) PetscCall(DMSwarmDataBucketCopyPoint(DBIn, list[p], *DB, list[p]));
534:   PetscFunctionReturn(PETSC_SUCCESS);
535: }

537: /* insert into an existing location */
538: PetscErrorCode DMSwarmDataFieldInsertPoint(const DMSwarmDataField field, const PetscInt index, const void *data)
539: {
540:   PetscFunctionBegin;
541: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
542:   /* check point is valid */
543:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
544:   PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
545: #endif
546:   PetscCall(PetscMemcpy(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), data, field->atomic_size));
547:   PetscFunctionReturn(PETSC_SUCCESS);
548: }

550: /* remove data at index - replace with last point */
551: PetscErrorCode DMSwarmDataBucketRemovePointAtIndex(const DMSwarmDataBucket db, const PetscInt index)
552: {
553:   PetscInt  f;
554:   PetscBool any_active_fields;

556:   PetscFunctionBegin;
557: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
558:   /* check point is valid */
559:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
560:   PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->L + db->buffer);
561: #endif
562:   PetscCall(DMSwarmDataBucketQueryForActiveFields(db, &any_active_fields));
563:   PetscCheck(!any_active_fields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot safely remove point as at least one DMSwarmDataField is currently being accessed");
564:   if (index >= db->L) { /* this point is not in the list - no need to error, but I will anyway */
565:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "You should not be trying to remove point at index=%" PetscInt_FMT " since it's < db->L = %" PetscInt_FMT, index, db->L);
566:   }
567:   if (index != db->L - 1) { /* not last point in list */
568:     for (f = 0; f < db->nfields; ++f) {
569:       DMSwarmDataField field = db->field[f];

571:       /* copy then remove */
572:       PetscCall(DMSwarmDataFieldCopyPoint(db->L - 1, field, index, field));
573:       /* DMSwarmDataFieldZeroPoint(field,index); */
574:     }
575:   }
576:   /* decrement size */
577:   /* this will zero out an crap at the end of the list */
578:   PetscCall(DMSwarmDataBucketRemovePoint(db));
579:   PetscFunctionReturn(PETSC_SUCCESS);
580: }

582: /* copy x into y */
583: PetscErrorCode DMSwarmDataFieldCopyPoint(const PetscInt pid_x, const DMSwarmDataField field_x, const PetscInt pid_y, const DMSwarmDataField field_y)
584: {
585:   PetscFunctionBegin;
586: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
587:   /* check point is valid */
588:   PetscCheck(pid_x >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be >= 0");
589:   PetscCheck(pid_x < field_x->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be < %" PetscInt_FMT, field_x->L);
590:   PetscCheck(pid_y >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be >= 0");
591:   PetscCheck(pid_y < field_y->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be < %" PetscInt_FMT, field_y->L);
592:   PetscCheck(field_y->atomic_size == field_x->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "atomic size must match");
593: #endif
594:   PetscCall(PetscMemcpy(DMSWARM_DATAFIELD_point_access(field_y->data, pid_y, field_y->atomic_size), DMSWARM_DATAFIELD_point_access(field_x->data, pid_x, field_x->atomic_size), field_y->atomic_size));
595:   PetscFunctionReturn(PETSC_SUCCESS);
596: }

598: /* zero only the datafield at this point */
599: PetscErrorCode DMSwarmDataFieldZeroPoint(const DMSwarmDataField field, const PetscInt index)
600: {
601:   PetscFunctionBegin;
602: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
603:   /* check point is valid */
604:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
605:   PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
606: #endif
607:   PetscCall(PetscMemzero(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), field->atomic_size));
608:   PetscFunctionReturn(PETSC_SUCCESS);
609: }

611: /* zero ALL data for this point */
612: PetscErrorCode DMSwarmDataBucketZeroPoint(const DMSwarmDataBucket db, const PetscInt index)
613: {
614:   PetscInt f;

616:   PetscFunctionBegin;
617:   /* check point is valid */
618:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
619:   PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->allocated);
620:   for (f = 0; f < db->nfields; ++f) {
621:     DMSwarmDataField field = db->field[f];
622:     PetscCall(DMSwarmDataFieldZeroPoint(field, index));
623:   }
624:   PetscFunctionReturn(PETSC_SUCCESS);
625: }

627: /* increment */
628: PetscErrorCode DMSwarmDataBucketAddPoint(DMSwarmDataBucket db)
629: {
630:   PetscFunctionBegin;
631:   PetscCall(DMSwarmDataBucketSetSizes(db, PetscMax(db->L, 0) + 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
632:   PetscFunctionReturn(PETSC_SUCCESS);
633: }

635: /* decrement */
636: PetscErrorCode DMSwarmDataBucketRemovePoint(DMSwarmDataBucket db)
637: {
638:   PetscFunctionBegin;
639:   PetscCheck(db->L > 0, PetscObjectComm((PetscObject)db), PETSC_ERR_ARG_WRONG, "Swarm has no points to be removed");
640:   PetscCall(DMSwarmDataBucketSetSizes(db, db->L - 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
641:   PetscFunctionReturn(PETSC_SUCCESS);
642: }

644: /*  Should be redone to user PetscViewer */
645: static PetscErrorCode DMSwarmDataBucketView_stdout(MPI_Comm comm, DMSwarmDataBucket db)
646: {
647:   PetscInt f;
648:   double   memory_usage_total = 0.0;

650:   PetscFunctionBegin;
651:   PetscCall(PetscPrintf(comm, "DMSwarmDataBucketView: \n"));
652:   PetscCall(PetscPrintf(comm, "  L                  = %" PetscInt_FMT " \n", db->L));
653:   PetscCall(PetscPrintf(comm, "  buffer             = %" PetscInt_FMT " \n", db->buffer));
654:   PetscCall(PetscPrintf(comm, "  allocated          = %" PetscInt_FMT " \n", db->allocated));
655:   PetscCall(PetscPrintf(comm, "  nfields registered = %" PetscInt_FMT " \n", db->nfields));

657:   for (f = 0; f < db->nfields; ++f) {
658:     double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
659:     memory_usage_total += memory_usage_f;
660:   }
661:   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &memory_usage_total, 1, MPI_DOUBLE, MPI_SUM, comm));

663:   for (f = 0; f < db->nfields; ++f) {
664:     double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
665:     PetscCall(PetscPrintf(comm, "    [%3" PetscInt_FMT "] %15s : Mem. usage       = %1.2e (MB) [rank0]\n", f, db->field[f]->name, memory_usage_f));
666:     PetscCall(PetscPrintf(comm, "                            blocksize        = %" PetscInt_FMT " \n", db->field[f]->bs));
667:     if (db->field[f]->bs != 1) {
668:       PetscCall(PetscPrintf(comm, "                            atomic size      = %zu [full block, bs=%" PetscInt_FMT "]\n", db->field[f]->atomic_size, db->field[f]->bs));
669:       PetscCall(PetscPrintf(comm, "                            atomic size/item = %zu \n", (size_t)(db->field[f]->atomic_size / db->field[f]->bs)));
670:     } else {
671:       PetscCall(PetscPrintf(comm, "                            atomic size      = %zu \n", db->field[f]->atomic_size));
672:     }
673:   }
674:   PetscCall(PetscPrintf(comm, "  Total mem. usage                           = %1.2e (MB) (collective)\n", memory_usage_total));
675:   PetscFunctionReturn(PETSC_SUCCESS);
676: }

678: static PetscErrorCode DMSwarmDataBucketView_Seq(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
679: {
680:   PetscFunctionBegin;
681:   switch (type) {
682:   case DATABUCKET_VIEW_STDOUT:
683:     PetscCall(DMSwarmDataBucketView_stdout(PETSC_COMM_SELF, db));
684:     break;
685:   case DATABUCKET_VIEW_ASCII:
686:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for ascii output");
687:   case DATABUCKET_VIEW_BINARY:
688:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for binary output");
689:   case DATABUCKET_VIEW_HDF5:
690:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for HDF5 output");
691:   default:
692:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer method requested");
693:   }
694:   PetscFunctionReturn(PETSC_SUCCESS);
695: }

697: static PetscErrorCode DMSwarmDataBucketView_MPI(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
698: {
699:   PetscFunctionBegin;
700:   switch (type) {
701:   case DATABUCKET_VIEW_STDOUT:
702:     PetscCall(DMSwarmDataBucketView_stdout(comm, db));
703:     break;
704:   case DATABUCKET_VIEW_ASCII:
705:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for ascii output");
706:   case DATABUCKET_VIEW_BINARY:
707:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for binary output");
708:   case DATABUCKET_VIEW_HDF5:
709:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for HDF5 output");
710:   default:
711:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer method requested");
712:   }
713:   PetscFunctionReturn(PETSC_SUCCESS);
714: }

716: PetscErrorCode DMSwarmDataBucketView(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
717: {
718:   PetscMPIInt size;

720:   PetscFunctionBegin;
721:   PetscCallMPI(MPI_Comm_size(comm, &size));
722:   if (size == 1) {
723:     PetscCall(DMSwarmDataBucketView_Seq(comm, db, filename, type));
724:   } else {
725:     PetscCall(DMSwarmDataBucketView_MPI(comm, db, filename, type));
726:   }
727:   PetscFunctionReturn(PETSC_SUCCESS);
728: }

730: PetscErrorCode DMSwarmDataBucketDuplicateFields(DMSwarmDataBucket dbA, DMSwarmDataBucket *dbB)
731: {
732:   DMSwarmDataBucket db2;
733:   PetscInt          f;

735:   PetscFunctionBegin;
736:   PetscCall(DMSwarmDataBucketCreate(&db2));
737:   /* copy contents from dbA into db2 */
738:   for (f = 0; f < dbA->nfields; ++f) {
739:     DMSwarmDataField field;
740:     size_t           atomic_size;
741:     char            *name;

743:     field       = dbA->field[f];
744:     atomic_size = field->atomic_size;
745:     name        = field->name;
746:     PetscCall(DMSwarmDataBucketRegisterField(db2, "DMSwarmDataBucketDuplicateFields", name, atomic_size, NULL));
747:   }
748:   PetscCall(DMSwarmDataBucketFinalize(db2));
749:   PetscCall(DMSwarmDataBucketSetInitialSizes(db2, 0, 1000));
750:   *dbB = db2;
751:   PetscFunctionReturn(PETSC_SUCCESS);
752: }

754: /*
755:  Insert points from db2 into db1
756:  db1 <<== db2
757:  */
758: PetscErrorCode DMSwarmDataBucketInsertValues(DMSwarmDataBucket db1, DMSwarmDataBucket db2)
759: {
760:   PetscInt n_mp_points1, n_mp_points2;
761:   PetscInt n_mp_points1_new;

763:   PetscFunctionBegin;
764:   PetscCall(DMSwarmDataBucketGetSizes(db1, &n_mp_points1, NULL, NULL));
765:   PetscCall(DMSwarmDataBucketGetSizes(db2, &n_mp_points2, NULL, NULL));
766:   n_mp_points1_new = n_mp_points1 + n_mp_points2;
767:   PetscCall(DMSwarmDataBucketSetSizes(db1, n_mp_points1_new, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
768:   for (PetscInt p = 0; p < n_mp_points2; ++p) {
769:     /* db1 <<== db2 */
770:     PetscCall(DMSwarmDataBucketCopyPoint(db2, p, db1, n_mp_points1 + p));
771:   }
772:   PetscFunctionReturn(PETSC_SUCCESS);
773: }

775: /* helpers for parallel send/recv */
776: PetscErrorCode DMSwarmDataBucketCreatePackedArray(DMSwarmDataBucket db, size_t *bytes, void **buf)
777: {
778:   size_t sizeof_marker_contents;
779:   void  *buffer;

781:   PetscFunctionBegin;
782:   sizeof_marker_contents = 0;
783:   for (PetscInt f = 0; f < db->nfields; ++f) {
784:     DMSwarmDataField df = db->field[f];
785:     sizeof_marker_contents += df->atomic_size;
786:   }
787:   PetscCall(PetscMalloc(sizeof_marker_contents, &buffer));
788:   PetscCall(PetscMemzero(buffer, sizeof_marker_contents));
789:   if (bytes) *bytes = sizeof_marker_contents;
790:   if (buf) *buf = buffer;
791:   PetscFunctionReturn(PETSC_SUCCESS);
792: }

794: PetscErrorCode DMSwarmDataBucketDestroyPackedArray(DMSwarmDataBucket db, void **buf)
795: {
796:   PetscFunctionBegin;
797:   if (buf) {
798:     PetscCall(PetscFree(*buf));
799:     *buf = NULL;
800:   }
801:   PetscFunctionReturn(PETSC_SUCCESS);
802: }

804: PetscErrorCode DMSwarmDataBucketFillPackedArray(DMSwarmDataBucket db, const PetscInt index, void *buf)
805: {
806:   void  *data, *data_p;
807:   size_t asize, offset;

809:   PetscFunctionBegin;
810:   offset = 0;
811:   for (PetscInt f = 0; f < db->nfields; ++f) {
812:     DMSwarmDataField df = db->field[f];

814:     asize  = df->atomic_size;
815:     data   = df->data;
816:     data_p = (void *)((char *)data + index * asize);
817:     PetscCall(PetscMemcpy((void *)((char *)buf + offset), data_p, asize));
818:     offset = offset + asize;
819:   }
820:   PetscFunctionReturn(PETSC_SUCCESS);
821: }

823: PetscErrorCode DMSwarmDataBucketInsertPackedArray(DMSwarmDataBucket db, const PetscInt idx, void *data)
824: {
825:   void  *data_p;
826:   size_t offset;

828:   PetscFunctionBegin;
829:   offset = 0;
830:   for (PetscInt f = 0; f < db->nfields; ++f) {
831:     DMSwarmDataField df = db->field[f];

833:     data_p = (void *)((char *)data + offset);
834:     PetscCall(DMSwarmDataFieldInsertPoint(df, idx, data_p));
835:     offset = offset + df->atomic_size;
836:   }
837:   PetscFunctionReturn(PETSC_SUCCESS);
838: }