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, current_used, new_used, new_unused, new_buffer, new_allocated, f, end;
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:   current_used      = PetscMax(db->L, 0);
249:   new_used          = L;
250:   new_unused        = current_allocated - new_used;
251:   new_buffer        = db->buffer;
252:   if (buffer >= 0) { /* update the buffer value */
253:     new_buffer = buffer;
254:   }
255:   new_allocated = new_used + new_buffer;
256:   /* action */
257:   if (new_allocated > current_allocated) {
258:     /* increase size to new_used + new_buffer and zero new space */
259:     for (f = 0; f < db->nfields; f++) {
260:       PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
261:       PetscCall(DMSwarmDataFieldZeroBlock(db->field[f], current_allocated, new_allocated));
262:     }
263:     db->L         = new_used;
264:     db->buffer    = new_buffer;
265:     db->allocated = new_used + new_buffer;
266:   } else {
267:     if (new_unused > 2 * new_buffer) {
268:       /* shrink array to new_used + new_buffer */
269:       for (f = 0; f < db->nfields; ++f) PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
270:       db->L         = new_used;
271:       db->buffer    = new_buffer;
272:       db->allocated = new_used + new_buffer;
273:     } else {
274:       db->L      = new_used;
275:       db->buffer = new_buffer;
276:     }
277:   }
278:   /* if we shrunk, zero old entries from new_used to current_used or end of array */
279:   end = PetscMin(current_used, new_allocated);
280:   if (end > new_used) {
281:     for (f = 0; f < db->nfields; ++f) {
282:       DMSwarmDataField field = db->field[f];
283:       PetscCall(DMSwarmDataFieldZeroBlock(field, new_used, end));
284:     }
285:   }
286:   PetscFunctionReturn(PETSC_SUCCESS);
287: }

289: PetscErrorCode DMSwarmDataBucketSetInitialSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
290: {
291:   PetscInt f;

293:   PetscFunctionBegin;
294:   PetscCall(DMSwarmDataBucketSetSizes(db, L, buffer));
295:   for (f = 0; f < db->nfields; ++f) {
296:     DMSwarmDataField field = db->field[f];
297:     PetscCall(DMSwarmDataFieldZeroBlock(field, 0, db->allocated));
298:   }
299:   PetscFunctionReturn(PETSC_SUCCESS);
300: }

302: PetscErrorCode DMSwarmDataBucketGetSizes(DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
303: {
304:   PetscFunctionBegin;
305:   if (L) *L = db->L;
306:   if (buffer) *buffer = db->buffer;
307:   if (allocated) *allocated = db->allocated;
308:   PetscFunctionReturn(PETSC_SUCCESS);
309: }

311: PetscErrorCode DMSwarmDataBucketGetGlobalSizes(MPI_Comm comm, DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
312: {
313:   PetscFunctionBegin;
314:   if (L) PetscCallMPI(MPIU_Allreduce(&db->L, L, 1, MPIU_INT, MPI_SUM, comm));
315:   if (buffer) PetscCallMPI(MPIU_Allreduce(&db->buffer, buffer, 1, MPIU_INT, MPI_SUM, comm));
316:   if (allocated) PetscCallMPI(MPIU_Allreduce(&db->allocated, allocated, 1, MPIU_INT, MPI_SUM, comm));
317:   PetscFunctionReturn(PETSC_SUCCESS);
318: }

320: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFields(DMSwarmDataBucket db, PetscInt *L, DMSwarmDataField *fields[])
321: {
322:   PetscFunctionBegin;
323:   if (L) *L = db->nfields;
324:   if (fields) *fields = db->field;
325:   PetscFunctionReturn(PETSC_SUCCESS);
326: }

328: PetscErrorCode DMSwarmDataFieldGetAccess(const DMSwarmDataField gfield)
329: {
330:   PetscFunctionBegin;
331:   PetscCheck(!gfield->active, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is already active. You must call DMSwarmDataFieldRestoreAccess()", gfield->name);
332:   gfield->active = PETSC_TRUE;
333:   PetscFunctionReturn(PETSC_SUCCESS);
334: }

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

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

369: PetscErrorCode DMSwarmDataFieldRestoreAccess(DMSwarmDataField gfield)
370: {
371:   PetscFunctionBegin;
372:   PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess()", gfield->name);
373:   gfield->active = PETSC_FALSE;
374:   PetscFunctionReturn(PETSC_SUCCESS);
375: }

377: PetscErrorCode DMSwarmDataFieldVerifyAccess(const DMSwarmDataField gfield, const size_t size)
378: {
379:   PetscFunctionBegin;
380: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
381:   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);
382: #endif
383:   PetscFunctionReturn(PETSC_SUCCESS);
384: }

386: PetscErrorCode DMSwarmDataFieldGetAtomicSize(const DMSwarmDataField gfield, size_t *size)
387: {
388:   PetscFunctionBegin;
389:   if (size) *size = gfield->atomic_size;
390:   PetscFunctionReturn(PETSC_SUCCESS);
391: }

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

400: PetscErrorCode DMSwarmDataFieldRestoreEntries(const DMSwarmDataField gfield, void **data)
401: {
402:   PetscFunctionBegin;
403:   if (data) *data = NULL;
404:   PetscFunctionReturn(PETSC_SUCCESS);
405: }

407: /* y = x */
408: PetscErrorCode DMSwarmDataBucketCopyPoint(const DMSwarmDataBucket xb, const PetscInt pid_x, const DMSwarmDataBucket yb, const PetscInt pid_y)
409: {
410:   PetscInt f;

412:   PetscFunctionBegin;
413:   for (f = 0; f < xb->nfields; ++f) {
414:     void *dest;
415:     void *src;

417:     PetscCall(DMSwarmDataFieldGetAccess(xb->field[f]));
418:     if (xb != yb) PetscCall(DMSwarmDataFieldGetAccess(yb->field[f]));
419:     PetscCall(DMSwarmDataFieldAccessPoint(xb->field[f], pid_x, &src));
420:     PetscCall(DMSwarmDataFieldAccessPoint(yb->field[f], pid_y, &dest));
421:     PetscCall(PetscMemcpy(dest, src, xb->field[f]->atomic_size));
422:     PetscCall(DMSwarmDataFieldRestoreAccess(xb->field[f]));
423:     if (xb != yb) PetscCall(DMSwarmDataFieldRestoreAccess(yb->field[f]));
424:   }
425:   PetscFunctionReturn(PETSC_SUCCESS);
426: }

428: PetscErrorCode DMSwarmDataBucketCreateFromSubset(DMSwarmDataBucket DBIn, const PetscInt N, const PetscInt list[], DMSwarmDataBucket *DB)
429: {
430:   PetscInt          nfields;
431:   DMSwarmDataField *fields;
432:   PetscInt          f, L, buffer, allocated, p;

434:   PetscFunctionBegin;
435:   PetscCall(DMSwarmDataBucketCreate(DB));
436:   /* copy contents of DBIn */
437:   PetscCall(DMSwarmDataBucketGetDMSwarmDataFields(DBIn, &nfields, &fields));
438:   PetscCall(DMSwarmDataBucketGetSizes(DBIn, &L, &buffer, &allocated));
439:   for (f = 0; f < nfields; ++f) PetscCall(DMSwarmDataBucketRegisterField(*DB, "DMSwarmDataBucketCreateFromSubset", fields[f]->name, fields[f]->atomic_size, NULL));
440:   PetscCall(DMSwarmDataBucketFinalize(*DB));
441:   PetscCall(DMSwarmDataBucketSetSizes(*DB, L, buffer));
442:   for (f = 0; f < nfields; ++f) {
443:     DMSwarmDataField gfield;

445:     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(*DB, fields[f]->name, &gfield));
446:     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, fields[f]->bs));
447:     gfield->petsc_type = fields[f]->petsc_type;
448:   }
449:   /* now copy the desired guys from DBIn => DB */
450:   for (p = 0; p < N; ++p) PetscCall(DMSwarmDataBucketCopyPoint(DBIn, list[p], *DB, list[p]));
451:   PetscFunctionReturn(PETSC_SUCCESS);
452: }

454: /* insert into an existing location */
455: PetscErrorCode DMSwarmDataFieldInsertPoint(const DMSwarmDataField field, const PetscInt index, const void *data)
456: {
457:   PetscFunctionBegin;
458: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
459:   /* check point is valid */
460:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
461:   PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
462: #endif
463:   PetscCall(PetscMemcpy(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), data, field->atomic_size));
464:   PetscFunctionReturn(PETSC_SUCCESS);
465: }

467: /* remove data at index - replace with last point */
468: PetscErrorCode DMSwarmDataBucketRemovePointAtIndex(const DMSwarmDataBucket db, const PetscInt index)
469: {
470:   PetscInt  f;
471:   PetscBool any_active_fields;

473:   PetscFunctionBegin;
474: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
475:   /* check point is valid */
476:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
477:   PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->L + db->buffer);
478: #endif
479:   PetscCall(DMSwarmDataBucketQueryForActiveFields(db, &any_active_fields));
480:   PetscCheck(!any_active_fields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot safely remove point as at least one DMSwarmDataField is currently being accessed");
481:   if (index >= db->L) { /* this point is not in the list - no need to error, but I will anyway */
482:     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);
483:   }
484:   if (index != db->L - 1) { /* not last point in list */
485:     for (f = 0; f < db->nfields; ++f) {
486:       DMSwarmDataField field = db->field[f];

488:       /* copy then remove */
489:       PetscCall(DMSwarmDataFieldCopyPoint(db->L - 1, field, index, field));
490:       /* DMSwarmDataFieldZeroPoint(field,index); */
491:     }
492:   }
493:   /* decrement size */
494:   /* this will zero out an crap at the end of the list */
495:   PetscCall(DMSwarmDataBucketRemovePoint(db));
496:   PetscFunctionReturn(PETSC_SUCCESS);
497: }

499: /* copy x into y */
500: PetscErrorCode DMSwarmDataFieldCopyPoint(const PetscInt pid_x, const DMSwarmDataField field_x, const PetscInt pid_y, const DMSwarmDataField field_y)
501: {
502:   PetscFunctionBegin;
503: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
504:   /* check point is valid */
505:   PetscCheck(pid_x >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be >= 0");
506:   PetscCheck(pid_x < field_x->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be < %" PetscInt_FMT, field_x->L);
507:   PetscCheck(pid_y >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be >= 0");
508:   PetscCheck(pid_y < field_y->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be < %" PetscInt_FMT, field_y->L);
509:   PetscCheck(field_y->atomic_size == field_x->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "atomic size must match");
510: #endif
511:   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));
512:   PetscFunctionReturn(PETSC_SUCCESS);
513: }

515: /* zero only the datafield at this point */
516: PetscErrorCode DMSwarmDataFieldZeroPoint(const DMSwarmDataField field, const PetscInt index)
517: {
518:   PetscFunctionBegin;
519: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
520:   /* check point is valid */
521:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
522:   PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
523: #endif
524:   PetscCall(PetscMemzero(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), field->atomic_size));
525:   PetscFunctionReturn(PETSC_SUCCESS);
526: }

528: /* zero ALL data for this point */
529: PetscErrorCode DMSwarmDataBucketZeroPoint(const DMSwarmDataBucket db, const PetscInt index)
530: {
531:   PetscInt f;

533:   PetscFunctionBegin;
534:   /* check point is valid */
535:   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
536:   PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->allocated);
537:   for (f = 0; f < db->nfields; ++f) {
538:     DMSwarmDataField field = db->field[f];
539:     PetscCall(DMSwarmDataFieldZeroPoint(field, index));
540:   }
541:   PetscFunctionReturn(PETSC_SUCCESS);
542: }

544: /* increment */
545: PetscErrorCode DMSwarmDataBucketAddPoint(DMSwarmDataBucket db)
546: {
547:   PetscFunctionBegin;
548:   PetscCall(DMSwarmDataBucketSetSizes(db, PetscMax(db->L, 0) + 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
549:   PetscFunctionReturn(PETSC_SUCCESS);
550: }

552: /* decrement */
553: PetscErrorCode DMSwarmDataBucketRemovePoint(DMSwarmDataBucket db)
554: {
555:   PetscFunctionBegin;
556:   PetscCheck(db->L > 0, PetscObjectComm((PetscObject)db), PETSC_ERR_ARG_WRONG, "Swarm has no points to be removed");
557:   PetscCall(DMSwarmDataBucketSetSizes(db, db->L - 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
558:   PetscFunctionReturn(PETSC_SUCCESS);
559: }

561: /*  Should be redone to user PetscViewer */
562: static PetscErrorCode DMSwarmDataBucketView_stdout(MPI_Comm comm, DMSwarmDataBucket db)
563: {
564:   PetscInt f;
565:   double   memory_usage_total = 0.0;

567:   PetscFunctionBegin;
568:   PetscCall(PetscPrintf(comm, "DMSwarmDataBucketView: \n"));
569:   PetscCall(PetscPrintf(comm, "  L                  = %" PetscInt_FMT " \n", db->L));
570:   PetscCall(PetscPrintf(comm, "  buffer             = %" PetscInt_FMT " \n", db->buffer));
571:   PetscCall(PetscPrintf(comm, "  allocated          = %" PetscInt_FMT " \n", db->allocated));
572:   PetscCall(PetscPrintf(comm, "  nfields registered = %" PetscInt_FMT " \n", db->nfields));

574:   for (f = 0; f < db->nfields; ++f) {
575:     double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
576:     memory_usage_total += memory_usage_f;
577:   }
578:   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &memory_usage_total, 1, MPI_DOUBLE, MPI_SUM, comm));

580:   for (f = 0; f < db->nfields; ++f) {
581:     double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
582:     PetscCall(PetscPrintf(comm, "    [%3" PetscInt_FMT "] %15s : Mem. usage       = %1.2e (MB) [rank0]\n", f, db->field[f]->name, memory_usage_f));
583:     PetscCall(PetscPrintf(comm, "                            blocksize        = %" PetscInt_FMT " \n", db->field[f]->bs));
584:     if (db->field[f]->bs != 1) {
585:       PetscCall(PetscPrintf(comm, "                            atomic size      = %zu [full block, bs=%" PetscInt_FMT "]\n", db->field[f]->atomic_size, db->field[f]->bs));
586:       PetscCall(PetscPrintf(comm, "                            atomic size/item = %zu \n", (size_t)(db->field[f]->atomic_size / db->field[f]->bs)));
587:     } else {
588:       PetscCall(PetscPrintf(comm, "                            atomic size      = %zu \n", db->field[f]->atomic_size));
589:     }
590:   }
591:   PetscCall(PetscPrintf(comm, "  Total mem. usage                           = %1.2e (MB) (collective)\n", memory_usage_total));
592:   PetscFunctionReturn(PETSC_SUCCESS);
593: }

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

614: static PetscErrorCode DMSwarmDataBucketView_MPI(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
615: {
616:   PetscFunctionBegin;
617:   switch (type) {
618:   case DATABUCKET_VIEW_STDOUT:
619:     PetscCall(DMSwarmDataBucketView_stdout(comm, db));
620:     break;
621:   case DATABUCKET_VIEW_ASCII:
622:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for ascii output");
623:   case DATABUCKET_VIEW_BINARY:
624:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for binary output");
625:   case DATABUCKET_VIEW_HDF5:
626:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for HDF5 output");
627:   default:
628:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer method requested");
629:   }
630:   PetscFunctionReturn(PETSC_SUCCESS);
631: }

633: PetscErrorCode DMSwarmDataBucketView(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
634: {
635:   PetscMPIInt size;

637:   PetscFunctionBegin;
638:   PetscCallMPI(MPI_Comm_size(comm, &size));
639:   if (size == 1) {
640:     PetscCall(DMSwarmDataBucketView_Seq(comm, db, filename, type));
641:   } else {
642:     PetscCall(DMSwarmDataBucketView_MPI(comm, db, filename, type));
643:   }
644:   PetscFunctionReturn(PETSC_SUCCESS);
645: }

647: PetscErrorCode DMSwarmDataBucketDuplicateFields(DMSwarmDataBucket dbA, DMSwarmDataBucket *dbB)
648: {
649:   DMSwarmDataBucket db2;
650:   PetscInt          f;

652:   PetscFunctionBegin;
653:   PetscCall(DMSwarmDataBucketCreate(&db2));
654:   /* copy contents from dbA into db2 */
655:   for (f = 0; f < dbA->nfields; ++f) {
656:     DMSwarmDataField field;
657:     size_t           atomic_size;
658:     char            *name;

660:     field       = dbA->field[f];
661:     atomic_size = field->atomic_size;
662:     name        = field->name;
663:     PetscCall(DMSwarmDataBucketRegisterField(db2, "DMSwarmDataBucketDuplicateFields", name, atomic_size, NULL));
664:   }
665:   PetscCall(DMSwarmDataBucketFinalize(db2));
666:   PetscCall(DMSwarmDataBucketSetInitialSizes(db2, 0, 1000));
667:   *dbB = db2;
668:   PetscFunctionReturn(PETSC_SUCCESS);
669: }

671: /*
672:  Insert points from db2 into db1
673:  db1 <<== db2
674:  */
675: PetscErrorCode DMSwarmDataBucketInsertValues(DMSwarmDataBucket db1, DMSwarmDataBucket db2)
676: {
677:   PetscInt n_mp_points1, n_mp_points2;
678:   PetscInt n_mp_points1_new, p;

680:   PetscFunctionBegin;
681:   PetscCall(DMSwarmDataBucketGetSizes(db1, &n_mp_points1, NULL, NULL));
682:   PetscCall(DMSwarmDataBucketGetSizes(db2, &n_mp_points2, NULL, NULL));
683:   n_mp_points1_new = n_mp_points1 + n_mp_points2;
684:   PetscCall(DMSwarmDataBucketSetSizes(db1, n_mp_points1_new, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
685:   for (p = 0; p < n_mp_points2; ++p) {
686:     /* db1 <<== db2 */
687:     PetscCall(DMSwarmDataBucketCopyPoint(db2, p, db1, n_mp_points1 + p));
688:   }
689:   PetscFunctionReturn(PETSC_SUCCESS);
690: }

692: /* helpers for parallel send/recv */
693: PetscErrorCode DMSwarmDataBucketCreatePackedArray(DMSwarmDataBucket db, size_t *bytes, void **buf)
694: {
695:   PetscInt f;
696:   size_t   sizeof_marker_contents;
697:   void    *buffer;

699:   PetscFunctionBegin;
700:   sizeof_marker_contents = 0;
701:   for (f = 0; f < db->nfields; ++f) {
702:     DMSwarmDataField df = db->field[f];
703:     sizeof_marker_contents += df->atomic_size;
704:   }
705:   PetscCall(PetscMalloc(sizeof_marker_contents, &buffer));
706:   PetscCall(PetscMemzero(buffer, sizeof_marker_contents));
707:   if (bytes) *bytes = sizeof_marker_contents;
708:   if (buf) *buf = buffer;
709:   PetscFunctionReturn(PETSC_SUCCESS);
710: }

712: PetscErrorCode DMSwarmDataBucketDestroyPackedArray(DMSwarmDataBucket db, void **buf)
713: {
714:   PetscFunctionBegin;
715:   if (buf) {
716:     PetscCall(PetscFree(*buf));
717:     *buf = NULL;
718:   }
719:   PetscFunctionReturn(PETSC_SUCCESS);
720: }

722: PetscErrorCode DMSwarmDataBucketFillPackedArray(DMSwarmDataBucket db, const PetscInt index, void *buf)
723: {
724:   PetscInt f;
725:   void    *data, *data_p;
726:   size_t   asize, offset;

728:   PetscFunctionBegin;
729:   offset = 0;
730:   for (f = 0; f < db->nfields; ++f) {
731:     DMSwarmDataField df = db->field[f];

733:     asize  = df->atomic_size;
734:     data   = df->data;
735:     data_p = (void *)((char *)data + index * asize);
736:     PetscCall(PetscMemcpy((void *)((char *)buf + offset), data_p, asize));
737:     offset = offset + asize;
738:   }
739:   PetscFunctionReturn(PETSC_SUCCESS);
740: }

742: PetscErrorCode DMSwarmDataBucketInsertPackedArray(DMSwarmDataBucket db, const PetscInt idx, void *data)
743: {
744:   PetscInt f;
745:   void    *data_p;
746:   size_t   offset;

748:   PetscFunctionBegin;
749:   offset = 0;
750:   for (f = 0; f < db->nfields; ++f) {
751:     DMSwarmDataField df = db->field[f];

753:     data_p = (void *)((char *)data + offset);
754:     PetscCall(DMSwarmDataFieldInsertPoint(df, idx, data_p));
755:     offset = offset + df->atomic_size;
756:   }
757:   PetscFunctionReturn(PETSC_SUCCESS);
758: }