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:   PetscInt i;

  8:   PetscFunctionBegin;
  9:   *val = PETSC_FALSE;
 10:   for (i = 0; i < N; ++i) {
 11:     PetscBool flg;
 12:     PetscCall(PetscStrcmp(name, gfield[i]->name, &flg));
 13:     if (flg) {
 14:       *val = PETSC_TRUE;
 15:       PetscFunctionReturn(PETSC_SUCCESS);
 16:     }
 17:   }
 18:   PetscFunctionReturn(PETSC_SUCCESS);
 19: }

 21: PetscErrorCode DMSwarmDataFieldStringFindInList(const char name[], const PetscInt N, const DMSwarmDataField gfield[], PetscInt *index)
 22: {
 23:   PetscInt i;

 25:   PetscFunctionBegin;
 26:   *index = -1;
 27:   for (i = 0; i < N; ++i) {
 28:     PetscBool flg;
 29:     PetscCall(PetscStrcmp(name, gfield[i]->name, &flg));
 30:     if (flg) {
 31:       *index = i;
 32:       PetscFunctionReturn(PETSC_SUCCESS);
 33:     }
 34:   }
 35:   PetscFunctionReturn(PETSC_SUCCESS);
 36: }

 38: PetscErrorCode DMSwarmDataFieldCreate(const char registration_function[], const char name[], const size_t size, const PetscInt L, DMSwarmDataField *DF)
 39: {
 40:   DMSwarmDataField df;

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

 56: PetscErrorCode DMSwarmDataFieldDestroy(DMSwarmDataField *DF)
 57: {
 58:   DMSwarmDataField df = *DF;

 60:   PetscFunctionBegin;
 61:   PetscCall(PetscFree(df->registration_function));
 62:   PetscCall(PetscFree(df->name));
 63:   PetscCall(PetscFree(df->data));
 64:   PetscCall(PetscFree(df));
 65:   *DF = NULL;
 66:   PetscFunctionReturn(PETSC_SUCCESS);
 67: }

 69: /* data bucket */
 70: PetscErrorCode DMSwarmDataBucketCreate(DMSwarmDataBucket *DB)
 71: {
 72:   DMSwarmDataBucket db;

 74:   PetscFunctionBegin;
 75:   PetscCall(PetscNew(&db));

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

 88: PetscErrorCode DMSwarmDataBucketDestroy(DMSwarmDataBucket *DB)
 89: {
 90:   DMSwarmDataBucket db = *DB;
 91:   PetscInt          f;

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

103: PetscErrorCode DMSwarmDataBucketQueryForActiveFields(DMSwarmDataBucket db, PetscBool *any_active_fields)
104: {
105:   PetscInt f;

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

118: PetscErrorCode DMSwarmDataBucketRegisterField(DMSwarmDataBucket db, const char registration_function[], const char field_name[], size_t atomic_size, DMSwarmDataField *_gfield)
119: {
120:   PetscBool        val;
121:   DMSwarmDataField fp;

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

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

153: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldIdByName(DMSwarmDataBucket db, const char name[], PetscInt *idx)
154: {
155:   PetscBool found;

157:   PetscFunctionBegin;
158:   *idx = -1;
159:   PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, &found));
160:   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot find DMSwarmDataField with name %s", name);
161:   PetscCall(DMSwarmDataFieldStringFindInList(name, db->nfields, (const DMSwarmDataField *)db->field, idx));
162:   PetscFunctionReturn(PETSC_SUCCESS);
163: }

165: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldByName(DMSwarmDataBucket db, const char name[], DMSwarmDataField *gfield)
166: {
167:   PetscInt  idx;
168:   PetscBool found;

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

178: PetscErrorCode DMSwarmDataBucketQueryDMSwarmDataFieldByName(DMSwarmDataBucket db, const char name[], PetscBool *found)
179: {
180:   PetscFunctionBegin;
181:   *found = PETSC_FALSE;
182:   PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, found));
183:   PetscFunctionReturn(PETSC_SUCCESS);
184: }

186: PetscErrorCode DMSwarmDataBucketFinalize(DMSwarmDataBucket db)
187: {
188:   PetscFunctionBegin;
189:   db->finalised = PETSC_TRUE;
190:   PetscFunctionReturn(PETSC_SUCCESS);
191: }

193: PetscErrorCode DMSwarmDataFieldGetNumEntries(DMSwarmDataField df, PetscInt *sum)
194: {
195:   PetscFunctionBegin;
196:   *sum = df->L;
197:   PetscFunctionReturn(PETSC_SUCCESS);
198: }

200: PetscErrorCode DMSwarmDataFieldSetBlockSize(DMSwarmDataField df, PetscInt blocksize)
201: {
202:   PetscFunctionBegin;
203:   df->bs = blocksize;
204:   PetscFunctionReturn(PETSC_SUCCESS);
205: }

207: PetscErrorCode DMSwarmDataFieldSetSize(DMSwarmDataField df, const PetscInt new_L)
208: {
209:   PetscFunctionBegin;
210:   PetscCheck(new_L >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot set size of DMSwarmDataField to be < 0");
211:   if (new_L == df->L) PetscFunctionReturn(PETSC_SUCCESS);
212:   if (new_L > df->L) {
213:     PetscCall(PetscRealloc(df->atomic_size * (new_L), &df->data));
214:     /* init new contents */
215:     PetscCall(PetscMemzero(((char *)df->data) + df->L * df->atomic_size, (new_L - df->L) * df->atomic_size));
216:   } else {
217:     /* reallocate pointer list, add +1 in case new_L = 0 */
218:     PetscCall(PetscRealloc(df->atomic_size * (new_L + 1), &df->data));
219:   }
220:   df->L = new_L;
221:   PetscFunctionReturn(PETSC_SUCCESS);
222: }

224: PetscErrorCode DMSwarmDataFieldZeroBlock(DMSwarmDataField df, const PetscInt start, const PetscInt end)
225: {
226:   PetscFunctionBegin;
227:   PetscCheck(start <= end, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") > end(%" PetscInt_FMT ")", start, end);
228:   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") < 0", start);
229:   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);
230:   PetscCall(PetscMemzero(((char *)df->data) + start * df->atomic_size, (end - start) * df->atomic_size));
231:   PetscFunctionReturn(PETSC_SUCCESS);
232: }

234: /*
235:  A negative buffer value will simply be ignored and the old buffer value will be used.
236:  */
237: PetscErrorCode DMSwarmDataBucketSetSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
238: {
239:   PetscInt  current_allocated, new_used, new_unused, new_buffer, new_allocated, f;
240:   PetscBool any_active_fields;

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

247:   current_allocated = db->allocated;
248:   new_used          = L;
249:   new_unused        = current_allocated - new_used;
250:   new_buffer        = db->buffer;
251:   if (buffer >= 0) { /* update the buffer value */
252:     new_buffer = buffer;
253:   }
254:   new_allocated = new_used + new_buffer;
255:   /* action */
256:   if (new_allocated > current_allocated) {
257:     /* increase size to new_used + new_buffer */
258:     for (f = 0; f < db->nfields; f++) PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
259:     db->L         = new_used;
260:     db->buffer    = new_buffer;
261:     db->allocated = new_used + new_buffer;
262:   } else {
263:     if (new_unused > 2 * new_buffer) {
264:       /* shrink array to new_used + new_buffer */
265:       for (f = 0; f < db->nfields; ++f) PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
266:       db->L         = new_used;
267:       db->buffer    = new_buffer;
268:       db->allocated = new_used + new_buffer;
269:     } else {
270:       db->L      = new_used;
271:       db->buffer = new_buffer;
272:     }
273:   }
274:   /* zero all entries from db->L to db->allocated */
275:   for (f = 0; f < db->nfields; ++f) {
276:     DMSwarmDataField field = db->field[f];
277:     PetscCall(DMSwarmDataFieldZeroBlock(field, db->L, db->allocated));
278:   }
279:   PetscFunctionReturn(PETSC_SUCCESS);
280: }

282: PetscErrorCode DMSwarmDataBucketSetInitialSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
283: {
284:   PetscInt f;

286:   PetscFunctionBegin;
287:   PetscCall(DMSwarmDataBucketSetSizes(db, L, buffer));
288:   for (f = 0; f < db->nfields; ++f) {
289:     DMSwarmDataField field = db->field[f];
290:     PetscCall(DMSwarmDataFieldZeroBlock(field, 0, db->allocated));
291:   }
292:   PetscFunctionReturn(PETSC_SUCCESS);
293: }

295: PetscErrorCode DMSwarmDataBucketGetSizes(DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
296: {
297:   PetscFunctionBegin;
298:   if (L) *L = db->L;
299:   if (buffer) *buffer = db->buffer;
300:   if (allocated) *allocated = db->allocated;
301:   PetscFunctionReturn(PETSC_SUCCESS);
302: }

304: PetscErrorCode DMSwarmDataBucketGetGlobalSizes(MPI_Comm comm, DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
305: {
306:   PetscFunctionBegin;
307:   if (L) PetscCallMPI(MPIU_Allreduce(&db->L, L, 1, MPIU_INT, MPI_SUM, comm));
308:   if (buffer) PetscCallMPI(MPIU_Allreduce(&db->buffer, buffer, 1, MPIU_INT, MPI_SUM, comm));
309:   if (allocated) PetscCallMPI(MPIU_Allreduce(&db->allocated, allocated, 1, MPIU_INT, MPI_SUM, comm));
310:   PetscFunctionReturn(PETSC_SUCCESS);
311: }

313: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFields(DMSwarmDataBucket db, PetscInt *L, DMSwarmDataField *fields[])
314: {
315:   PetscFunctionBegin;
316:   if (L) *L = db->nfields;
317:   if (fields) *fields = db->field;
318:   PetscFunctionReturn(PETSC_SUCCESS);
319: }

321: PetscErrorCode DMSwarmDataFieldGetAccess(const DMSwarmDataField gfield)
322: {
323:   PetscFunctionBegin;
324:   PetscCheck(!gfield->active, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is already active. You must call DMSwarmDataFieldRestoreAccess()", gfield->name);
325:   gfield->active = PETSC_TRUE;
326:   PetscFunctionReturn(PETSC_SUCCESS);
327: }

329: PetscErrorCode DMSwarmDataFieldAccessPoint(const DMSwarmDataField gfield, const PetscInt pid, void **ctx_p)
330: {
331:   PetscFunctionBegin;
332:   *ctx_p = NULL;
333: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
334:   /* debug mode */
335:   /* check point is valid */
336:   PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
337:   PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
338:   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);
339: #endif
340:   *ctx_p = DMSWARM_DATAFIELD_point_access(gfield->data, pid, gfield->atomic_size);
341:   PetscFunctionReturn(PETSC_SUCCESS);
342: }

344: PetscErrorCode DMSwarmDataFieldAccessPointOffset(const DMSwarmDataField gfield, const size_t offset, const PetscInt pid, void **ctx_p)
345: {
346:   PetscFunctionBegin;
347: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
348:   /* debug mode */
349:   /* check point is valid */
350:   /* PetscCheck(offset >= 0,PETSC_COMM_SELF,PETSC_ERR_USER,"offset must be >= 0");*/
351:   /* Note compiler realizes this can never happen with an unsigned PetscInt */
352:   PetscCheck(offset < gfield->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "offset must be < %zu", gfield->atomic_size);
353:   /* check point is valid */
354:   PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
355:   PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
356:   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);
357: #endif
358:   *ctx_p = DMSWARM_DATAFIELD_point_access_offset(gfield->data, pid, gfield->atomic_size, offset);
359:   PetscFunctionReturn(PETSC_SUCCESS);
360: }

362: PetscErrorCode DMSwarmDataFieldRestoreAccess(DMSwarmDataField gfield)
363: {
364:   PetscFunctionBegin;
365:   PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess()", gfield->name);
366:   gfield->active = PETSC_FALSE;
367:   PetscFunctionReturn(PETSC_SUCCESS);
368: }

370: PetscErrorCode DMSwarmDataFieldVerifyAccess(const DMSwarmDataField gfield, const size_t size)
371: {
372:   PetscFunctionBegin;
373: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
374:   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);
375: #endif
376:   PetscFunctionReturn(PETSC_SUCCESS);
377: }

379: PetscErrorCode DMSwarmDataFieldGetAtomicSize(const DMSwarmDataField gfield, size_t *size)
380: {
381:   PetscFunctionBegin;
382:   if (size) *size = gfield->atomic_size;
383:   PetscFunctionReturn(PETSC_SUCCESS);
384: }

386: PetscErrorCode DMSwarmDataFieldGetEntries(const DMSwarmDataField gfield, void **data)
387: {
388:   PetscFunctionBegin;
389:   if (data) *data = gfield->data;
390:   PetscFunctionReturn(PETSC_SUCCESS);
391: }

393: PetscErrorCode DMSwarmDataFieldRestoreEntries(const DMSwarmDataField gfield, void **data)
394: {
395:   PetscFunctionBegin;
396:   if (data) *data = NULL;
397:   PetscFunctionReturn(PETSC_SUCCESS);
398: }

400: /* y = x */
401: PetscErrorCode DMSwarmDataBucketCopyPoint(const DMSwarmDataBucket xb, const PetscInt pid_x, const DMSwarmDataBucket yb, const PetscInt pid_y)
402: {
403:   PetscInt f;

405:   PetscFunctionBegin;
406:   for (f = 0; f < xb->nfields; ++f) {
407:     void *dest;
408:     void *src;

410:     PetscCall(DMSwarmDataFieldGetAccess(xb->field[f]));
411:     if (xb != yb) PetscCall(DMSwarmDataFieldGetAccess(yb->field[f]));
412:     PetscCall(DMSwarmDataFieldAccessPoint(xb->field[f], pid_x, &src));
413:     PetscCall(DMSwarmDataFieldAccessPoint(yb->field[f], pid_y, &dest));
414:     PetscCall(PetscMemcpy(dest, src, xb->field[f]->atomic_size));
415:     PetscCall(DMSwarmDataFieldRestoreAccess(xb->field[f]));
416:     if (xb != yb) PetscCall(DMSwarmDataFieldRestoreAccess(yb->field[f]));
417:   }
418:   PetscFunctionReturn(PETSC_SUCCESS);
419: }

421: PetscErrorCode DMSwarmDataBucketCreateFromSubset(DMSwarmDataBucket DBIn, const PetscInt N, const PetscInt list[], DMSwarmDataBucket *DB)
422: {
423:   PetscInt          nfields;
424:   DMSwarmDataField *fields;
425:   PetscInt          f, L, buffer, allocated, p;

427:   PetscFunctionBegin;
428:   PetscCall(DMSwarmDataBucketCreate(DB));
429:   /* copy contents of DBIn */
430:   PetscCall(DMSwarmDataBucketGetDMSwarmDataFields(DBIn, &nfields, &fields));
431:   PetscCall(DMSwarmDataBucketGetSizes(DBIn, &L, &buffer, &allocated));
432:   for (f = 0; f < nfields; ++f) PetscCall(DMSwarmDataBucketRegisterField(*DB, "DMSwarmDataBucketCreateFromSubset", fields[f]->name, fields[f]->atomic_size, NULL));
433:   PetscCall(DMSwarmDataBucketFinalize(*DB));
434:   PetscCall(DMSwarmDataBucketSetSizes(*DB, L, buffer));
435:   /* now copy the desired guys from DBIn => DB */
436:   for (p = 0; p < N; ++p) PetscCall(DMSwarmDataBucketCopyPoint(DBIn, list[p], *DB, list[p]));
437:   PetscFunctionReturn(PETSC_SUCCESS);
438: }

440: /* insert into an existing location */
441: PetscErrorCode DMSwarmDataFieldInsertPoint(const DMSwarmDataField field, const PetscInt index, const void *ctx)
442: {
443:   PetscFunctionBegin;
444: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
445:   /* check point is valid */
446:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
447:   PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
448: #endif
449:   PetscCall(PetscMemcpy(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), ctx, field->atomic_size));
450:   PetscFunctionReturn(PETSC_SUCCESS);
451: }

453: /* remove data at index - replace with last point */
454: PetscErrorCode DMSwarmDataBucketRemovePointAtIndex(const DMSwarmDataBucket db, const PetscInt index)
455: {
456:   PetscInt  f;
457:   PetscBool any_active_fields;

459:   PetscFunctionBegin;
460: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
461:   /* check point is valid */
462:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
463:   PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->L + db->buffer);
464: #endif
465:   PetscCall(DMSwarmDataBucketQueryForActiveFields(db, &any_active_fields));
466:   PetscCheck(!any_active_fields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot safely remove point as at least one DMSwarmDataField is currently being accessed");
467:   if (index >= db->L) { /* this point is not in the list - no need to error, but I will anyway */
468:     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);
469:   }
470:   if (index != db->L - 1) { /* not last point in list */
471:     for (f = 0; f < db->nfields; ++f) {
472:       DMSwarmDataField field = db->field[f];

474:       /* copy then remove */
475:       PetscCall(DMSwarmDataFieldCopyPoint(db->L - 1, field, index, field));
476:       /* DMSwarmDataFieldZeroPoint(field,index); */
477:     }
478:   }
479:   /* decrement size */
480:   /* this will zero out an crap at the end of the list */
481:   PetscCall(DMSwarmDataBucketRemovePoint(db));
482:   PetscFunctionReturn(PETSC_SUCCESS);
483: }

485: /* copy x into y */
486: PetscErrorCode DMSwarmDataFieldCopyPoint(const PetscInt pid_x, const DMSwarmDataField field_x, const PetscInt pid_y, const DMSwarmDataField field_y)
487: {
488:   PetscFunctionBegin;
489: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
490:   /* check point is valid */
491:   PetscCheck(pid_x >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be >= 0");
492:   PetscCheck(pid_x < field_x->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be < %" PetscInt_FMT, field_x->L);
493:   PetscCheck(pid_y >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be >= 0");
494:   PetscCheck(pid_y < field_y->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be < %" PetscInt_FMT, field_y->L);
495:   PetscCheck(field_y->atomic_size == field_x->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "atomic size must match");
496: #endif
497:   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));
498:   PetscFunctionReturn(PETSC_SUCCESS);
499: }

501: /* zero only the datafield at this point */
502: PetscErrorCode DMSwarmDataFieldZeroPoint(const DMSwarmDataField field, const PetscInt index)
503: {
504:   PetscFunctionBegin;
505: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
506:   /* check point is valid */
507:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
508:   PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
509: #endif
510:   PetscCall(PetscMemzero(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), field->atomic_size));
511:   PetscFunctionReturn(PETSC_SUCCESS);
512: }

514: /* zero ALL data for this point */
515: PetscErrorCode DMSwarmDataBucketZeroPoint(const DMSwarmDataBucket db, const PetscInt index)
516: {
517:   PetscInt f;

519:   PetscFunctionBegin;
520:   /* check point is valid */
521:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
522:   PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->allocated);
523:   for (f = 0; f < db->nfields; ++f) {
524:     DMSwarmDataField field = db->field[f];
525:     PetscCall(DMSwarmDataFieldZeroPoint(field, index));
526:   }
527:   PetscFunctionReturn(PETSC_SUCCESS);
528: }

530: /* increment */
531: PetscErrorCode DMSwarmDataBucketAddPoint(DMSwarmDataBucket db)
532: {
533:   PetscFunctionBegin;
534:   PetscCall(DMSwarmDataBucketSetSizes(db, db->L + 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
535:   PetscFunctionReturn(PETSC_SUCCESS);
536: }

538: /* decrement */
539: PetscErrorCode DMSwarmDataBucketRemovePoint(DMSwarmDataBucket db)
540: {
541:   PetscFunctionBegin;
542:   PetscCall(DMSwarmDataBucketSetSizes(db, db->L - 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
543:   PetscFunctionReturn(PETSC_SUCCESS);
544: }

546: /*  Should be redone to user PetscViewer */
547: static PetscErrorCode DMSwarmDataBucketView_stdout(MPI_Comm comm, DMSwarmDataBucket db)
548: {
549:   PetscInt f;
550:   double   memory_usage_total, memory_usage_total_local = 0.0;

552:   PetscFunctionBegin;
553:   PetscCall(PetscPrintf(comm, "DMSwarmDataBucketView: \n"));
554:   PetscCall(PetscPrintf(comm, "  L                  = %" PetscInt_FMT " \n", db->L));
555:   PetscCall(PetscPrintf(comm, "  buffer             = %" PetscInt_FMT " \n", db->buffer));
556:   PetscCall(PetscPrintf(comm, "  allocated          = %" PetscInt_FMT " \n", db->allocated));
557:   PetscCall(PetscPrintf(comm, "  nfields registered = %" PetscInt_FMT " \n", db->nfields));

559:   for (f = 0; f < db->nfields; ++f) {
560:     double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
561:     memory_usage_total_local += memory_usage_f;
562:   }
563:   PetscCallMPI(MPIU_Allreduce(&memory_usage_total_local, &memory_usage_total, 1, MPI_DOUBLE, MPI_SUM, comm));

565:   for (f = 0; f < db->nfields; ++f) {
566:     double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
567:     PetscCall(PetscPrintf(comm, "    [%3" PetscInt_FMT "] %15s : Mem. usage       = %1.2e (MB) [rank0]\n", f, db->field[f]->name, memory_usage_f));
568:     PetscCall(PetscPrintf(comm, "                            blocksize        = %" PetscInt_FMT " \n", db->field[f]->bs));
569:     if (db->field[f]->bs != 1) {
570:       PetscCall(PetscPrintf(comm, "                            atomic size      = %zu [full block, bs=%" PetscInt_FMT "]\n", db->field[f]->atomic_size, db->field[f]->bs));
571:       PetscCall(PetscPrintf(comm, "                            atomic size/item = %zu \n", (size_t)(db->field[f]->atomic_size / db->field[f]->bs)));
572:     } else {
573:       PetscCall(PetscPrintf(comm, "                            atomic size      = %zu \n", db->field[f]->atomic_size));
574:     }
575:   }
576:   PetscCall(PetscPrintf(comm, "  Total mem. usage                           = %1.2e (MB) (collective)\n", memory_usage_total));
577:   PetscFunctionReturn(PETSC_SUCCESS);
578: }

580: static PetscErrorCode DMSwarmDataBucketView_Seq(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
581: {
582:   PetscFunctionBegin;
583:   switch (type) {
584:   case DATABUCKET_VIEW_STDOUT:
585:     PetscCall(DMSwarmDataBucketView_stdout(PETSC_COMM_SELF, db));
586:     break;
587:   case DATABUCKET_VIEW_ASCII:
588:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for ascii output");
589:   case DATABUCKET_VIEW_BINARY:
590:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for binary output");
591:   case DATABUCKET_VIEW_HDF5:
592:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for HDF5 output");
593:   default:
594:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer method requested");
595:   }
596:   PetscFunctionReturn(PETSC_SUCCESS);
597: }

599: static PetscErrorCode DMSwarmDataBucketView_MPI(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
600: {
601:   PetscFunctionBegin;
602:   switch (type) {
603:   case DATABUCKET_VIEW_STDOUT:
604:     PetscCall(DMSwarmDataBucketView_stdout(comm, db));
605:     break;
606:   case DATABUCKET_VIEW_ASCII:
607:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for ascii output");
608:   case DATABUCKET_VIEW_BINARY:
609:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for binary output");
610:   case DATABUCKET_VIEW_HDF5:
611:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for HDF5 output");
612:   default:
613:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer method requested");
614:   }
615:   PetscFunctionReturn(PETSC_SUCCESS);
616: }

618: PetscErrorCode DMSwarmDataBucketView(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
619: {
620:   PetscMPIInt size;

622:   PetscFunctionBegin;
623:   PetscCallMPI(MPI_Comm_size(comm, &size));
624:   if (size == 1) {
625:     PetscCall(DMSwarmDataBucketView_Seq(comm, db, filename, type));
626:   } else {
627:     PetscCall(DMSwarmDataBucketView_MPI(comm, db, filename, type));
628:   }
629:   PetscFunctionReturn(PETSC_SUCCESS);
630: }

632: PetscErrorCode DMSwarmDataBucketDuplicateFields(DMSwarmDataBucket dbA, DMSwarmDataBucket *dbB)
633: {
634:   DMSwarmDataBucket db2;
635:   PetscInt          f;

637:   PetscFunctionBegin;
638:   PetscCall(DMSwarmDataBucketCreate(&db2));
639:   /* copy contents from dbA into db2 */
640:   for (f = 0; f < dbA->nfields; ++f) {
641:     DMSwarmDataField field;
642:     size_t           atomic_size;
643:     char            *name;

645:     field       = dbA->field[f];
646:     atomic_size = field->atomic_size;
647:     name        = field->name;
648:     PetscCall(DMSwarmDataBucketRegisterField(db2, "DMSwarmDataBucketDuplicateFields", name, atomic_size, NULL));
649:   }
650:   PetscCall(DMSwarmDataBucketFinalize(db2));
651:   PetscCall(DMSwarmDataBucketSetInitialSizes(db2, 0, 1000));
652:   *dbB = db2;
653:   PetscFunctionReturn(PETSC_SUCCESS);
654: }

656: /*
657:  Insert points from db2 into db1
658:  db1 <<== db2
659:  */
660: PetscErrorCode DMSwarmDataBucketInsertValues(DMSwarmDataBucket db1, DMSwarmDataBucket db2)
661: {
662:   PetscInt n_mp_points1, n_mp_points2;
663:   PetscInt n_mp_points1_new, p;

665:   PetscFunctionBegin;
666:   PetscCall(DMSwarmDataBucketGetSizes(db1, &n_mp_points1, NULL, NULL));
667:   PetscCall(DMSwarmDataBucketGetSizes(db2, &n_mp_points2, NULL, NULL));
668:   n_mp_points1_new = n_mp_points1 + n_mp_points2;
669:   PetscCall(DMSwarmDataBucketSetSizes(db1, n_mp_points1_new, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
670:   for (p = 0; p < n_mp_points2; ++p) {
671:     /* db1 <<== db2 */
672:     PetscCall(DMSwarmDataBucketCopyPoint(db2, p, db1, n_mp_points1 + p));
673:   }
674:   PetscFunctionReturn(PETSC_SUCCESS);
675: }

677: /* helpers for parallel send/recv */
678: PetscErrorCode DMSwarmDataBucketCreatePackedArray(DMSwarmDataBucket db, size_t *bytes, void **buf)
679: {
680:   PetscInt f;
681:   size_t   sizeof_marker_contents;
682:   void    *buffer;

684:   PetscFunctionBegin;
685:   sizeof_marker_contents = 0;
686:   for (f = 0; f < db->nfields; ++f) {
687:     DMSwarmDataField df = db->field[f];
688:     sizeof_marker_contents += df->atomic_size;
689:   }
690:   PetscCall(PetscMalloc(sizeof_marker_contents, &buffer));
691:   PetscCall(PetscMemzero(buffer, sizeof_marker_contents));
692:   if (bytes) *bytes = sizeof_marker_contents;
693:   if (buf) *buf = buffer;
694:   PetscFunctionReturn(PETSC_SUCCESS);
695: }

697: PetscErrorCode DMSwarmDataBucketDestroyPackedArray(DMSwarmDataBucket db, void **buf)
698: {
699:   PetscFunctionBegin;
700:   if (buf) {
701:     PetscCall(PetscFree(*buf));
702:     *buf = NULL;
703:   }
704:   PetscFunctionReturn(PETSC_SUCCESS);
705: }

707: PetscErrorCode DMSwarmDataBucketFillPackedArray(DMSwarmDataBucket db, const PetscInt index, void *buf)
708: {
709:   PetscInt f;
710:   void    *data, *data_p;
711:   size_t   asize, offset;

713:   PetscFunctionBegin;
714:   offset = 0;
715:   for (f = 0; f < db->nfields; ++f) {
716:     DMSwarmDataField df = db->field[f];

718:     asize  = df->atomic_size;
719:     data   = (void *)df->data;
720:     data_p = (void *)((char *)data + index * asize);
721:     PetscCall(PetscMemcpy((void *)((char *)buf + offset), data_p, asize));
722:     offset = offset + asize;
723:   }
724:   PetscFunctionReturn(PETSC_SUCCESS);
725: }

727: PetscErrorCode DMSwarmDataBucketInsertPackedArray(DMSwarmDataBucket db, const PetscInt idx, void *data)
728: {
729:   PetscInt f;
730:   void    *data_p;
731:   size_t   offset;

733:   PetscFunctionBegin;
734:   offset = 0;
735:   for (f = 0; f < db->nfields; ++f) {
736:     DMSwarmDataField df = db->field[f];

738:     data_p = (void *)((char *)data + offset);
739:     PetscCall(DMSwarmDataFieldInsertPoint(df, idx, (void *)data_p));
740:     offset = offset + df->atomic_size;
741:   }
742:   PetscFunctionReturn(PETSC_SUCCESS);
743: }