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: /*@C
154:   DMSwarmDataBucketGetDMSwarmDataFieldIdByName - Return the index of a `DMSwarmDataField` within a `DMSwarmDataBucket` given its name.

156:   Not Collective

158:   Input Parameters:
159: + db   - the `DMSwarmDataBucket`
160: - name - the field name

162:   Output Parameter:
163: . idx - the index of the field within the bucket

165:   Level: developer

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

170: .seealso: `DMSwarmDataBucket`, `DMSwarmDataField`, `DMSwarmDataBucketGetDMSwarmDataFieldByName()`, `DMSwarmDataBucketQueryDMSwarmDataFieldByName()`
171: @*/
172: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldIdByName(DMSwarmDataBucket db, const char name[], PetscInt *idx)
173: {
174:   PetscBool found;

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

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

187:   Not Collective

189:   Input Parameters:
190: + db   - the `DMSwarmDataBucket`
191: - name - the field name

193:   Output Parameter:
194: . gfield - the `DMSwarmDataField` handle

196:   Level: developer

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

201: .seealso: `DMSwarmDataBucket`, `DMSwarmDataField`, `DMSwarmDataBucketGetDMSwarmDataFieldIdByName()`, `DMSwarmDataBucketQueryDMSwarmDataFieldByName()`
202: @*/
203: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldByName(DMSwarmDataBucket db, const char name[], DMSwarmDataField *gfield)
204: {
205:   PetscInt  idx;
206:   PetscBool found;

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

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

219:   Not Collective

221:   Input Parameters:
222: + db   - the `DMSwarmDataBucket`
223: - name - the field name to look up

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

228:   Level: developer

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

240: PetscErrorCode DMSwarmDataBucketFinalize(DMSwarmDataBucket db)
241: {
242:   PetscFunctionBegin;
243:   db->finalised = PETSC_TRUE;
244:   PetscFunctionReturn(PETSC_SUCCESS);
245: }

247: PetscErrorCode DMSwarmDataFieldGetNumEntries(DMSwarmDataField df, PetscInt *sum)
248: {
249:   PetscFunctionBegin;
250:   *sum = df->L;
251:   PetscFunctionReturn(PETSC_SUCCESS);
252: }

254: PetscErrorCode DMSwarmDataFieldSetBlockSize(DMSwarmDataField df, PetscInt blocksize)
255: {
256:   PetscFunctionBegin;
257:   df->bs = blocksize;
258:   PetscFunctionReturn(PETSC_SUCCESS);
259: }

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

278: PetscErrorCode DMSwarmDataFieldZeroBlock(DMSwarmDataField df, const PetscInt start, const PetscInt end)
279: {
280:   PetscFunctionBegin;
281:   PetscCheck(start <= end, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") > end(%" PetscInt_FMT ")", start, end);
282:   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") < 0", start);
283:   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);
284:   PetscCall(PetscMemzero(((char *)df->data) + start * df->atomic_size, (end - start) * df->atomic_size));
285:   PetscFunctionReturn(PETSC_SUCCESS);
286: }

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

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

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

343: PetscErrorCode DMSwarmDataBucketSetInitialSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
344: {
345:   PetscInt f;

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

356: PetscErrorCode DMSwarmDataBucketGetSizes(DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
357: {
358:   PetscFunctionBegin;
359:   if (L) *L = db->L;
360:   if (buffer) *buffer = db->buffer;
361:   if (allocated) *allocated = db->allocated;
362:   PetscFunctionReturn(PETSC_SUCCESS);
363: }

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

374: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFields(DMSwarmDataBucket db, PetscInt *L, DMSwarmDataField *fields[])
375: {
376:   PetscFunctionBegin;
377:   if (L) *L = db->nfields;
378:   if (fields) *fields = db->field;
379:   PetscFunctionReturn(PETSC_SUCCESS);
380: }

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

390: PetscErrorCode DMSwarmDataFieldAccessPoint(const DMSwarmDataField gfield, const PetscInt pid, void **ctx_p)
391: {
392:   PetscFunctionBegin;
393:   *ctx_p = NULL;
394: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
395:   /* debug mode */
396:   /* check point is valid */
397:   PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
398:   PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
399:   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);
400: #endif
401:   *ctx_p = DMSWARM_DATAFIELD_point_access(gfield->data, pid, gfield->atomic_size);
402:   PetscFunctionReturn(PETSC_SUCCESS);
403: }

405: PetscErrorCode DMSwarmDataFieldAccessPointOffset(const DMSwarmDataField gfield, const size_t offset, const PetscInt pid, void **ctx_p)
406: {
407:   PetscFunctionBegin;
408: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
409:   /* debug mode */
410:   /* check point is valid */
411:   /* PetscCheck(offset >= 0,PETSC_COMM_SELF,PETSC_ERR_USER,"offset must be >= 0");*/
412:   /* Note compiler realizes this can never happen with an unsigned PetscInt */
413:   PetscCheck(offset < gfield->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "offset must be < %zu", gfield->atomic_size);
414:   /* check point is valid */
415:   PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
416:   PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
417:   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);
418: #endif
419:   *ctx_p = DMSWARM_DATAFIELD_point_access_offset(gfield->data, pid, gfield->atomic_size, offset);
420:   PetscFunctionReturn(PETSC_SUCCESS);
421: }

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

431: PetscErrorCode DMSwarmDataFieldVerifyAccess(const DMSwarmDataField gfield, const size_t size)
432: {
433:   PetscFunctionBegin;
434: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
435:   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);
436: #endif
437:   PetscFunctionReturn(PETSC_SUCCESS);
438: }

440: PetscErrorCode DMSwarmDataFieldGetAtomicSize(const DMSwarmDataField gfield, size_t *size)
441: {
442:   PetscFunctionBegin;
443:   if (size) *size = gfield->atomic_size;
444:   PetscFunctionReturn(PETSC_SUCCESS);
445: }

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

450:   Not Collective

452:   Input Parameter:
453: . gfield - the `DMSwarmDataField`

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

458:   Level: developer

460:   Note:
461:   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.

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

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

475:   Not Collective

477:   Input Parameter:
478: . gfield - the `DMSwarmDataField`

480:   Output Parameter:
481: . data - pointer that will be set to `NULL`

483:   Level: developer

485: .seealso: `DMSwarmDataField`, `DMSwarmDataFieldGetEntries()`
486: @*/
487: PetscErrorCode DMSwarmDataFieldRestoreEntries(const DMSwarmDataField gfield, void **data)
488: {
489:   PetscFunctionBegin;
490:   if (data) *data = NULL;
491:   PetscFunctionReturn(PETSC_SUCCESS);
492: }

494: /* y = x */
495: PetscErrorCode DMSwarmDataBucketCopyPoint(const DMSwarmDataBucket xb, const PetscInt pid_x, const DMSwarmDataBucket yb, const PetscInt pid_y)
496: {
497:   PetscInt f;

499:   PetscFunctionBegin;
500:   for (f = 0; f < xb->nfields; ++f) {
501:     void *dest;
502:     void *src;

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

515: PetscErrorCode DMSwarmDataBucketCreateFromSubset(DMSwarmDataBucket DBIn, const PetscInt N, const PetscInt list[], DMSwarmDataBucket *DB)
516: {
517:   PetscInt          nfields;
518:   DMSwarmDataField *fields;
519:   PetscInt          f, L, buffer, allocated, p;

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

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

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

554: /* remove data at index - replace with last point */
555: PetscErrorCode DMSwarmDataBucketRemovePointAtIndex(const DMSwarmDataBucket db, const PetscInt index)
556: {
557:   PetscInt  f;
558:   PetscBool any_active_fields;

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

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

586: /* copy x into y */
587: PetscErrorCode DMSwarmDataFieldCopyPoint(const PetscInt pid_x, const DMSwarmDataField field_x, const PetscInt pid_y, const DMSwarmDataField field_y)
588: {
589:   PetscFunctionBegin;
590: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
591:   /* check point is valid */
592:   PetscCheck(pid_x >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be >= 0");
593:   PetscCheck(pid_x < field_x->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be < %" PetscInt_FMT, field_x->L);
594:   PetscCheck(pid_y >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be >= 0");
595:   PetscCheck(pid_y < field_y->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be < %" PetscInt_FMT, field_y->L);
596:   PetscCheck(field_y->atomic_size == field_x->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "atomic size must match");
597: #endif
598:   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));
599:   PetscFunctionReturn(PETSC_SUCCESS);
600: }

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

615: /* zero ALL data for this point */
616: PetscErrorCode DMSwarmDataBucketZeroPoint(const DMSwarmDataBucket db, const PetscInt index)
617: {
618:   PetscInt f;

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

631: /* increment */
632: PetscErrorCode DMSwarmDataBucketAddPoint(DMSwarmDataBucket db)
633: {
634:   PetscFunctionBegin;
635:   PetscCall(DMSwarmDataBucketSetSizes(db, PetscMax(db->L, 0) + 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
636:   PetscFunctionReturn(PETSC_SUCCESS);
637: }

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

648: /*  Should be redone to user PetscViewer */
649: static PetscErrorCode DMSwarmDataBucketView_stdout(MPI_Comm comm, DMSwarmDataBucket db)
650: {
651:   PetscInt f;
652:   double   memory_usage_total = 0.0;

654:   PetscFunctionBegin;
655:   PetscCall(PetscPrintf(comm, "DMSwarmDataBucketView: \n"));
656:   PetscCall(PetscPrintf(comm, "  L                  = %" PetscInt_FMT " \n", db->L));
657:   PetscCall(PetscPrintf(comm, "  buffer             = %" PetscInt_FMT " \n", db->buffer));
658:   PetscCall(PetscPrintf(comm, "  allocated          = %" PetscInt_FMT " \n", db->allocated));
659:   PetscCall(PetscPrintf(comm, "  nfields registered = %" PetscInt_FMT " \n", db->nfields));

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

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

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

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

720: PetscErrorCode DMSwarmDataBucketView(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
721: {
722:   PetscMPIInt size;

724:   PetscFunctionBegin;
725:   PetscCallMPI(MPI_Comm_size(comm, &size));
726:   if (size == 1) {
727:     PetscCall(DMSwarmDataBucketView_Seq(comm, db, filename, type));
728:   } else {
729:     PetscCall(DMSwarmDataBucketView_MPI(comm, db, filename, type));
730:   }
731:   PetscFunctionReturn(PETSC_SUCCESS);
732: }

734: PetscErrorCode DMSwarmDataBucketDuplicateFields(DMSwarmDataBucket dbA, DMSwarmDataBucket *dbB)
735: {
736:   DMSwarmDataBucket db2;
737:   PetscInt          f;

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

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

758: /*
759:  Insert points from db2 into db1
760:  db1 <<== db2
761:  */
762: PetscErrorCode DMSwarmDataBucketInsertValues(DMSwarmDataBucket db1, DMSwarmDataBucket db2)
763: {
764:   PetscInt n_mp_points1, n_mp_points2;
765:   PetscInt n_mp_points1_new, p;

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

779: /* helpers for parallel send/recv */
780: PetscErrorCode DMSwarmDataBucketCreatePackedArray(DMSwarmDataBucket db, size_t *bytes, void **buf)
781: {
782:   PetscInt f;
783:   size_t   sizeof_marker_contents;
784:   void    *buffer;

786:   PetscFunctionBegin;
787:   sizeof_marker_contents = 0;
788:   for (f = 0; f < db->nfields; ++f) {
789:     DMSwarmDataField df = db->field[f];
790:     sizeof_marker_contents += df->atomic_size;
791:   }
792:   PetscCall(PetscMalloc(sizeof_marker_contents, &buffer));
793:   PetscCall(PetscMemzero(buffer, sizeof_marker_contents));
794:   if (bytes) *bytes = sizeof_marker_contents;
795:   if (buf) *buf = buffer;
796:   PetscFunctionReturn(PETSC_SUCCESS);
797: }

799: PetscErrorCode DMSwarmDataBucketDestroyPackedArray(DMSwarmDataBucket db, void **buf)
800: {
801:   PetscFunctionBegin;
802:   if (buf) {
803:     PetscCall(PetscFree(*buf));
804:     *buf = NULL;
805:   }
806:   PetscFunctionReturn(PETSC_SUCCESS);
807: }

809: PetscErrorCode DMSwarmDataBucketFillPackedArray(DMSwarmDataBucket db, const PetscInt index, void *buf)
810: {
811:   PetscInt f;
812:   void    *data, *data_p;
813:   size_t   asize, offset;

815:   PetscFunctionBegin;
816:   offset = 0;
817:   for (f = 0; f < db->nfields; ++f) {
818:     DMSwarmDataField df = db->field[f];

820:     asize  = df->atomic_size;
821:     data   = df->data;
822:     data_p = (void *)((char *)data + index * asize);
823:     PetscCall(PetscMemcpy((void *)((char *)buf + offset), data_p, asize));
824:     offset = offset + asize;
825:   }
826:   PetscFunctionReturn(PETSC_SUCCESS);
827: }

829: PetscErrorCode DMSwarmDataBucketInsertPackedArray(DMSwarmDataBucket db, const PetscInt idx, void *data)
830: {
831:   PetscInt f;
832:   void    *data_p;
833:   size_t   offset;

835:   PetscFunctionBegin;
836:   offset = 0;
837:   for (f = 0; f < db->nfields; ++f) {
838:     DMSwarmDataField df = db->field[f];

840:     data_p = (void *)((char *)data + offset);
841:     PetscCall(DMSwarmDataFieldInsertPoint(df, idx, data_p));
842:     offset = offset + df->atomic_size;
843:   }
844:   PetscFunctionReturn(PETSC_SUCCESS);
845: }