Actual source code: data_bucket.c
1: #include "../src/dm/impls/swarm/data_bucket.h"
3: /* string helpers */
4: PetscErrorCode DMSwarmDataFieldStringInList(const char name[], const PetscInt N, const DMSwarmDataField gfield[], PetscBool *val)
5: {
6: PetscFunctionBegin;
7: *val = PETSC_FALSE;
8: for (PetscInt i = 0; i < N; ++i) {
9: PetscBool flg;
10: PetscCall(PetscStrcmp(name, gfield[i]->name, &flg));
11: if (flg) {
12: *val = PETSC_TRUE;
13: PetscFunctionReturn(PETSC_SUCCESS);
14: }
15: }
16: PetscFunctionReturn(PETSC_SUCCESS);
17: }
19: PetscErrorCode DMSwarmDataFieldStringFindInList(const char name[], const PetscInt N, const DMSwarmDataField gfield[], PetscInt *index)
20: {
21: PetscFunctionBegin;
22: *index = -1;
23: for (PetscInt i = 0; i < N; ++i) {
24: PetscBool flg;
25: PetscCall(PetscStrcmp(name, gfield[i]->name, &flg));
26: if (flg) {
27: *index = i;
28: PetscFunctionReturn(PETSC_SUCCESS);
29: }
30: }
31: PetscFunctionReturn(PETSC_SUCCESS);
32: }
34: PetscErrorCode DMSwarmDataFieldCreate(const char registration_function[], const char name[], const size_t size, const PetscInt L, DMSwarmDataField *DF)
35: {
36: DMSwarmDataField df;
38: PetscFunctionBegin;
39: PetscCall(PetscNew(&df));
40: PetscCall(PetscStrallocpy(registration_function, &df->registration_function));
41: PetscCall(PetscStrallocpy(name, &df->name));
42: df->atomic_size = size;
43: df->L = L;
44: df->bs = 1;
45: /* allocate something so we don't have to reallocate */
46: PetscCall(PetscMalloc(size * L, &df->data));
47: PetscCall(PetscMemzero(df->data, size * L));
48: *DF = df;
49: PetscFunctionReturn(PETSC_SUCCESS);
50: }
52: PetscErrorCode DMSwarmDataFieldDestroy(DMSwarmDataField *DF)
53: {
54: DMSwarmDataField df = *DF;
56: PetscFunctionBegin;
57: PetscCall(PetscFree(df->registration_function));
58: PetscCall(PetscFree(df->name));
59: PetscCall(PetscFree(df->data));
60: PetscCall(PetscFree(df));
61: *DF = NULL;
62: PetscFunctionReturn(PETSC_SUCCESS);
63: }
65: /* data bucket */
66: PetscErrorCode DMSwarmDataBucketCreate(DMSwarmDataBucket *DB)
67: {
68: DMSwarmDataBucket db;
70: PetscFunctionBegin;
71: PetscCall(PetscNew(&db));
73: db->finalised = PETSC_FALSE;
74: /* create empty spaces for fields */
75: db->L = -1;
76: db->buffer = 1;
77: db->allocated = 1;
78: db->nfields = 0;
79: PetscCall(PetscMalloc1(1, &db->field));
80: *DB = db;
81: PetscFunctionReturn(PETSC_SUCCESS);
82: }
84: PetscErrorCode DMSwarmDataBucketDestroy(DMSwarmDataBucket *DB)
85: {
86: DMSwarmDataBucket db = *DB;
87: PetscInt f;
89: PetscFunctionBegin;
90: /* release fields */
91: for (f = 0; f < db->nfields; ++f) PetscCall(DMSwarmDataFieldDestroy(&db->field[f]));
92: /* this will catch the initially allocated objects in the event that no fields are registered */
93: if (db->field != NULL) PetscCall(PetscFree(db->field));
94: PetscCall(PetscFree(db));
95: *DB = NULL;
96: PetscFunctionReturn(PETSC_SUCCESS);
97: }
99: PetscErrorCode DMSwarmDataBucketQueryForActiveFields(DMSwarmDataBucket db, PetscBool *any_active_fields)
100: {
101: PetscInt f;
103: PetscFunctionBegin;
104: *any_active_fields = PETSC_FALSE;
105: for (f = 0; f < db->nfields; ++f) {
106: if (db->field[f]->active) {
107: *any_active_fields = PETSC_TRUE;
108: PetscFunctionReturn(PETSC_SUCCESS);
109: }
110: }
111: PetscFunctionReturn(PETSC_SUCCESS);
112: }
114: PetscErrorCode DMSwarmDataBucketRegisterField(DMSwarmDataBucket db, const char registration_function[], const char field_name[], size_t atomic_size, DMSwarmDataField *_gfield)
115: {
116: PetscBool val;
117: DMSwarmDataField fp;
119: PetscFunctionBegin;
120: /* check we haven't finalised the registration of fields */
121: /*
122: if (db->finalised==PETSC_TRUE) {
123: printf("ERROR: DMSwarmDataBucketFinalize() has been called. Cannot register more fields\n");
124: ERROR();
125: }
126: */
127: /* check for repeated name */
128: PetscCall(DMSwarmDataFieldStringInList(field_name, db->nfields, (const DMSwarmDataField *)db->field, &val));
129: PetscCheck(val != PETSC_TRUE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field %s already exists. Cannot add same field twice", field_name);
130: /* create new space for data */
131: PetscCall(PetscRealloc(sizeof(DMSwarmDataField) * (db->nfields + 1), &db->field));
132: /* add field */
133: PetscCall(DMSwarmDataFieldCreate(registration_function, field_name, atomic_size, db->allocated, &fp));
134: db->field[db->nfields] = fp;
135: db->nfields++;
136: if (_gfield != NULL) *_gfield = fp;
137: PetscFunctionReturn(PETSC_SUCCESS);
138: }
140: /*
141: #define DMSwarmDataBucketRegisterField(db,name,size,k) {\
142: char *location;\
143: asprintf(&location,"Registered by %s() at line %d within file %s", __FUNCTION__, __LINE__, __FILE__);\
144: _DMSwarmDataBucketRegisterField( (db), location, (name), (size), (k));\
145: ierr = PetscFree(location);\
146: }
147: */
149: /*@C
150: DMSwarmDataBucketGetDMSwarmDataFieldIdByName - Return the index of a `DMSwarmDataField` within a `DMSwarmDataBucket` given its name.
152: Not Collective
154: Input Parameters:
155: + db - the `DMSwarmDataBucket`
156: - name - the field name
158: Output Parameter:
159: . idx - the index of the field within the bucket
161: Level: developer
163: Note:
164: Errors if no field with the given name is registered; use `DMSwarmDataBucketQueryDMSwarmDataFieldByName()` first when the name may be absent.
166: .seealso: `DMSwarmDataBucket`, `DMSwarmDataField`, `DMSwarmDataBucketGetDMSwarmDataFieldByName()`, `DMSwarmDataBucketQueryDMSwarmDataFieldByName()`
167: @*/
168: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldIdByName(DMSwarmDataBucket db, const char name[], PetscInt *idx)
169: {
170: PetscBool found;
172: PetscFunctionBegin;
173: *idx = -1;
174: PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, &found));
175: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot find DMSwarmDataField with name %s", name);
176: PetscCall(DMSwarmDataFieldStringFindInList(name, db->nfields, (const DMSwarmDataField *)db->field, idx));
177: PetscFunctionReturn(PETSC_SUCCESS);
178: }
180: /*@C
181: DMSwarmDataBucketGetDMSwarmDataFieldByName - Return the `DMSwarmDataField` handle registered in a `DMSwarmDataBucket` under a given name.
183: Not Collective
185: Input Parameters:
186: + db - the `DMSwarmDataBucket`
187: - name - the field name
189: Output Parameter:
190: . gfield - the `DMSwarmDataField` handle
192: Level: developer
194: Note:
195: Errors if no field with the given name is registered; use `DMSwarmDataBucketQueryDMSwarmDataFieldByName()` first when the name may be absent.
197: .seealso: `DMSwarmDataBucket`, `DMSwarmDataField`, `DMSwarmDataBucketGetDMSwarmDataFieldIdByName()`, `DMSwarmDataBucketQueryDMSwarmDataFieldByName()`
198: @*/
199: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldByName(DMSwarmDataBucket db, const char name[], DMSwarmDataField *gfield)
200: {
201: PetscInt idx;
202: PetscBool found;
204: PetscFunctionBegin;
205: PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, &found));
206: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot find DMSwarmDataField with name %s", name);
207: PetscCall(DMSwarmDataFieldStringFindInList(name, db->nfields, (const DMSwarmDataField *)db->field, &idx));
208: *gfield = db->field[idx];
209: PetscFunctionReturn(PETSC_SUCCESS);
210: }
212: /*@C
213: DMSwarmDataBucketQueryDMSwarmDataFieldByName - Test whether a `DMSwarmDataBucket` contains a `DMSwarmDataField` with the given name.
215: Not Collective
217: Input Parameters:
218: + db - the `DMSwarmDataBucket`
219: - name - the field name to look up
221: Output Parameter:
222: . found - `PETSC_TRUE` if a field with the given name is registered, otherwise `PETSC_FALSE`
224: Level: developer
226: .seealso: `DMSwarmDataBucket`, `DMSwarmDataField`, `DMSwarmDataBucketGetDMSwarmDataFieldByName()`, `DMSwarmDataBucketGetDMSwarmDataFieldIdByName()`
227: @*/
228: PetscErrorCode DMSwarmDataBucketQueryDMSwarmDataFieldByName(DMSwarmDataBucket db, const char name[], PetscBool *found)
229: {
230: PetscFunctionBegin;
231: *found = PETSC_FALSE;
232: PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, found));
233: PetscFunctionReturn(PETSC_SUCCESS);
234: }
236: PetscErrorCode DMSwarmDataBucketFinalize(DMSwarmDataBucket db)
237: {
238: PetscFunctionBegin;
239: db->finalised = PETSC_TRUE;
240: PetscFunctionReturn(PETSC_SUCCESS);
241: }
243: PetscErrorCode DMSwarmDataFieldGetNumEntries(DMSwarmDataField df, PetscInt *sum)
244: {
245: PetscFunctionBegin;
246: *sum = df->L;
247: PetscFunctionReturn(PETSC_SUCCESS);
248: }
250: PetscErrorCode DMSwarmDataFieldSetBlockSize(DMSwarmDataField df, PetscInt blocksize)
251: {
252: PetscFunctionBegin;
253: df->bs = blocksize;
254: PetscFunctionReturn(PETSC_SUCCESS);
255: }
257: PetscErrorCode DMSwarmDataFieldSetSize(DMSwarmDataField df, const PetscInt new_L)
258: {
259: PetscFunctionBegin;
260: PetscCheck(new_L >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot set size of DMSwarmDataField to be < 0");
261: if (new_L == df->L) PetscFunctionReturn(PETSC_SUCCESS);
262: if (new_L > df->L) {
263: PetscCall(PetscRealloc(df->atomic_size * (new_L), &df->data));
264: /* init new contents */
265: PetscCall(PetscMemzero(((char *)df->data) + df->L * df->atomic_size, (new_L - df->L) * df->atomic_size));
266: } else {
267: /* reallocate pointer list, add +1 in case new_L = 0 */
268: PetscCall(PetscRealloc(df->atomic_size * (new_L + 1), &df->data));
269: }
270: df->L = new_L;
271: PetscFunctionReturn(PETSC_SUCCESS);
272: }
274: PetscErrorCode DMSwarmDataFieldZeroBlock(DMSwarmDataField df, const PetscInt start, const PetscInt end)
275: {
276: PetscFunctionBegin;
277: PetscCheck(start <= end, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") > end(%" PetscInt_FMT ")", start, end);
278: PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") < 0", start);
279: PetscCheck(end <= df->L, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if end(%" PetscInt_FMT ") >= array size(%" PetscInt_FMT ")", end, df->L);
280: PetscCall(PetscMemzero(((char *)df->data) + start * df->atomic_size, (end - start) * df->atomic_size));
281: PetscFunctionReturn(PETSC_SUCCESS);
282: }
284: /*
285: A negative buffer value will simply be ignored and the old buffer value will be used.
286: */
287: PetscErrorCode DMSwarmDataBucketSetSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
288: {
289: PetscInt current_allocated, current_used, new_used, new_unused, new_buffer, new_allocated, f, end;
290: PetscBool any_active_fields;
292: PetscFunctionBegin;
293: PetscCheck(db->finalised != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "You must call DMSwarmDataBucketFinalize() before DMSwarmDataBucketSetSizes()");
294: PetscCall(DMSwarmDataBucketQueryForActiveFields(db, &any_active_fields));
295: PetscCheck(!any_active_fields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot safely re-size as at least one DMSwarmDataField is currently being accessed");
297: current_allocated = db->allocated;
298: current_used = PetscMax(db->L, 0);
299: new_used = L;
300: new_unused = current_allocated - new_used;
301: new_buffer = db->buffer;
302: if (buffer >= 0) { /* update the buffer value */
303: new_buffer = buffer;
304: }
305: new_allocated = new_used + new_buffer;
306: /* action */
307: if (new_allocated > current_allocated) {
308: /* increase size to new_used + new_buffer and zero new space */
309: for (f = 0; f < db->nfields; f++) {
310: PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
311: PetscCall(DMSwarmDataFieldZeroBlock(db->field[f], current_allocated, new_allocated));
312: }
313: db->L = new_used;
314: db->buffer = new_buffer;
315: db->allocated = new_used + new_buffer;
316: } else {
317: if (new_unused > 2 * new_buffer) {
318: /* shrink array to new_used + new_buffer */
319: for (f = 0; f < db->nfields; ++f) PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
320: db->L = new_used;
321: db->buffer = new_buffer;
322: db->allocated = new_used + new_buffer;
323: } else {
324: db->L = new_used;
325: db->buffer = new_buffer;
326: }
327: }
328: /* if we shrunk, zero old entries from new_used to current_used or end of array */
329: end = PetscMin(current_used, new_allocated);
330: if (end > new_used) {
331: for (f = 0; f < db->nfields; ++f) {
332: DMSwarmDataField field = db->field[f];
333: PetscCall(DMSwarmDataFieldZeroBlock(field, new_used, end));
334: }
335: }
336: PetscFunctionReturn(PETSC_SUCCESS);
337: }
339: PetscErrorCode DMSwarmDataBucketSetInitialSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
340: {
341: PetscInt f;
343: PetscFunctionBegin;
344: PetscCall(DMSwarmDataBucketSetSizes(db, L, buffer));
345: for (f = 0; f < db->nfields; ++f) {
346: DMSwarmDataField field = db->field[f];
347: PetscCall(DMSwarmDataFieldZeroBlock(field, 0, db->allocated));
348: }
349: PetscFunctionReturn(PETSC_SUCCESS);
350: }
352: PetscErrorCode DMSwarmDataBucketGetSizes(DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
353: {
354: PetscFunctionBegin;
355: if (L) *L = db->L;
356: if (buffer) *buffer = db->buffer;
357: if (allocated) *allocated = db->allocated;
358: PetscFunctionReturn(PETSC_SUCCESS);
359: }
361: PetscErrorCode DMSwarmDataBucketGetGlobalSizes(MPI_Comm comm, DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
362: {
363: PetscFunctionBegin;
364: if (L) PetscCallMPI(MPIU_Allreduce(&db->L, L, 1, MPIU_INT, MPI_SUM, comm));
365: if (buffer) PetscCallMPI(MPIU_Allreduce(&db->buffer, buffer, 1, MPIU_INT, MPI_SUM, comm));
366: if (allocated) PetscCallMPI(MPIU_Allreduce(&db->allocated, allocated, 1, MPIU_INT, MPI_SUM, comm));
367: PetscFunctionReturn(PETSC_SUCCESS);
368: }
370: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFields(DMSwarmDataBucket db, PetscInt *L, DMSwarmDataField *fields[])
371: {
372: PetscFunctionBegin;
373: if (L) *L = db->nfields;
374: if (fields) *fields = db->field;
375: PetscFunctionReturn(PETSC_SUCCESS);
376: }
378: PetscErrorCode DMSwarmDataFieldGetAccess(const DMSwarmDataField gfield)
379: {
380: PetscFunctionBegin;
381: PetscCheck(!gfield->active, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is already active. You must call DMSwarmDataFieldRestoreAccess()", gfield->name);
382: gfield->active = PETSC_TRUE;
383: PetscFunctionReturn(PETSC_SUCCESS);
384: }
386: PetscErrorCode DMSwarmDataFieldAccessPoint(const DMSwarmDataField gfield, const PetscInt pid, void **ctx_p)
387: {
388: PetscFunctionBegin;
389: *ctx_p = NULL;
390: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
391: /* debug mode */
392: /* check point is valid */
393: PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
394: PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
395: PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess() before point data can be retrivied", gfield->name);
396: #endif
397: *ctx_p = DMSWARM_DATAFIELD_point_access(gfield->data, pid, gfield->atomic_size);
398: PetscFunctionReturn(PETSC_SUCCESS);
399: }
401: PetscErrorCode DMSwarmDataFieldAccessPointOffset(const DMSwarmDataField gfield, const size_t offset, const PetscInt pid, void **ctx_p)
402: {
403: PetscFunctionBegin;
404: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
405: /* debug mode */
406: /* check point is valid */
407: /* PetscCheck(offset >= 0,PETSC_COMM_SELF,PETSC_ERR_USER,"offset must be >= 0");*/
408: /* Note compiler realizes this can never happen with an unsigned PetscInt */
409: PetscCheck(offset < gfield->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "offset must be < %zu", gfield->atomic_size);
410: /* check point is valid */
411: PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
412: PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
413: PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess() before point data can be retrivied", gfield->name);
414: #endif
415: *ctx_p = DMSWARM_DATAFIELD_point_access_offset(gfield->data, pid, gfield->atomic_size, offset);
416: PetscFunctionReturn(PETSC_SUCCESS);
417: }
419: PetscErrorCode DMSwarmDataFieldRestoreAccess(DMSwarmDataField gfield)
420: {
421: PetscFunctionBegin;
422: PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess()", gfield->name);
423: gfield->active = PETSC_FALSE;
424: PetscFunctionReturn(PETSC_SUCCESS);
425: }
427: PetscErrorCode DMSwarmDataFieldVerifyAccess(const DMSwarmDataField gfield, const size_t size)
428: {
429: PetscFunctionBegin;
430: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
431: PetscCheck(gfield->atomic_size == size, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" must be mapped to %zu bytes, your intended structure is %zu bytes in length.", gfield->name, gfield->atomic_size, size);
432: #endif
433: PetscFunctionReturn(PETSC_SUCCESS);
434: }
436: PetscErrorCode DMSwarmDataFieldGetAtomicSize(const DMSwarmDataField gfield, size_t *size)
437: {
438: PetscFunctionBegin;
439: if (size) *size = gfield->atomic_size;
440: PetscFunctionReturn(PETSC_SUCCESS);
441: }
443: /*@C
444: DMSwarmDataFieldGetEntries - Return a pointer to the raw contiguous storage backing a `DMSwarmDataField`.
446: Not Collective
448: Input Parameter:
449: . gfield - the `DMSwarmDataField`
451: Output Parameter:
452: . data - pointer to the raw entries; must be released with `DMSwarmDataFieldRestoreEntries()`
454: Level: developer
456: Note:
457: The array has `L * bs` entries of `atomic_size` bytes, where `L` is the number of particles and `bs` is the block size of the field.
459: .seealso: `DMSwarmDataField`, `DMSwarmDataFieldRestoreEntries()`, `DMSwarmDataFieldGetNumEntries()`, `DMSwarmDataFieldGetAtomicSize()`
460: @*/
461: PetscErrorCode DMSwarmDataFieldGetEntries(const DMSwarmDataField gfield, void **data)
462: {
463: PetscFunctionBegin;
464: if (data) *data = gfield->data;
465: PetscFunctionReturn(PETSC_SUCCESS);
466: }
468: /*@C
469: DMSwarmDataFieldRestoreEntries - Release a pointer obtained from `DMSwarmDataFieldGetEntries()`, clearing the caller's handle to `NULL`.
471: Not Collective
473: Input Parameter:
474: . gfield - the `DMSwarmDataField`
476: Output Parameter:
477: . data - pointer that will be set to `NULL`
479: Level: developer
481: .seealso: `DMSwarmDataField`, `DMSwarmDataFieldGetEntries()`
482: @*/
483: PetscErrorCode DMSwarmDataFieldRestoreEntries(const DMSwarmDataField gfield, void **data)
484: {
485: PetscFunctionBegin;
486: if (data) *data = NULL;
487: PetscFunctionReturn(PETSC_SUCCESS);
488: }
490: /* y = x */
491: PetscErrorCode DMSwarmDataBucketCopyPoint(const DMSwarmDataBucket xb, const PetscInt pid_x, const DMSwarmDataBucket yb, const PetscInt pid_y)
492: {
493: PetscInt f;
495: PetscFunctionBegin;
496: for (f = 0; f < xb->nfields; ++f) {
497: void *dest;
498: void *src;
500: PetscCall(DMSwarmDataFieldGetAccess(xb->field[f]));
501: if (xb != yb) PetscCall(DMSwarmDataFieldGetAccess(yb->field[f]));
502: PetscCall(DMSwarmDataFieldAccessPoint(xb->field[f], pid_x, &src));
503: PetscCall(DMSwarmDataFieldAccessPoint(yb->field[f], pid_y, &dest));
504: PetscCall(PetscMemcpy(dest, src, xb->field[f]->atomic_size));
505: PetscCall(DMSwarmDataFieldRestoreAccess(xb->field[f]));
506: if (xb != yb) PetscCall(DMSwarmDataFieldRestoreAccess(yb->field[f]));
507: }
508: PetscFunctionReturn(PETSC_SUCCESS);
509: }
511: PetscErrorCode DMSwarmDataBucketCreateFromSubset(DMSwarmDataBucket DBIn, const PetscInt N, const PetscInt list[], DMSwarmDataBucket *DB)
512: {
513: PetscInt nfields;
514: DMSwarmDataField *fields;
515: PetscInt f, L, buffer, allocated, p;
517: PetscFunctionBegin;
518: PetscCall(DMSwarmDataBucketCreate(DB));
519: /* copy contents of DBIn */
520: PetscCall(DMSwarmDataBucketGetDMSwarmDataFields(DBIn, &nfields, &fields));
521: PetscCall(DMSwarmDataBucketGetSizes(DBIn, &L, &buffer, &allocated));
522: for (f = 0; f < nfields; ++f) PetscCall(DMSwarmDataBucketRegisterField(*DB, "DMSwarmDataBucketCreateFromSubset", fields[f]->name, fields[f]->atomic_size, NULL));
523: PetscCall(DMSwarmDataBucketFinalize(*DB));
524: PetscCall(DMSwarmDataBucketSetSizes(*DB, L, buffer));
525: for (f = 0; f < nfields; ++f) {
526: DMSwarmDataField gfield;
528: PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(*DB, fields[f]->name, &gfield));
529: PetscCall(DMSwarmDataFieldSetBlockSize(gfield, fields[f]->bs));
530: gfield->petsc_type = fields[f]->petsc_type;
531: }
532: /* now copy the desired guys from DBIn => DB */
533: for (p = 0; p < N; ++p) PetscCall(DMSwarmDataBucketCopyPoint(DBIn, list[p], *DB, list[p]));
534: PetscFunctionReturn(PETSC_SUCCESS);
535: }
537: /* insert into an existing location */
538: PetscErrorCode DMSwarmDataFieldInsertPoint(const DMSwarmDataField field, const PetscInt index, const void *data)
539: {
540: PetscFunctionBegin;
541: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
542: /* check point is valid */
543: PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
544: PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
545: #endif
546: PetscCall(PetscMemcpy(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), data, field->atomic_size));
547: PetscFunctionReturn(PETSC_SUCCESS);
548: }
550: /* remove data at index - replace with last point */
551: PetscErrorCode DMSwarmDataBucketRemovePointAtIndex(const DMSwarmDataBucket db, const PetscInt index)
552: {
553: PetscInt f;
554: PetscBool any_active_fields;
556: PetscFunctionBegin;
557: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
558: /* check point is valid */
559: PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
560: PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->L + db->buffer);
561: #endif
562: PetscCall(DMSwarmDataBucketQueryForActiveFields(db, &any_active_fields));
563: PetscCheck(!any_active_fields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot safely remove point as at least one DMSwarmDataField is currently being accessed");
564: if (index >= db->L) { /* this point is not in the list - no need to error, but I will anyway */
565: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "You should not be trying to remove point at index=%" PetscInt_FMT " since it's < db->L = %" PetscInt_FMT, index, db->L);
566: }
567: if (index != db->L - 1) { /* not last point in list */
568: for (f = 0; f < db->nfields; ++f) {
569: DMSwarmDataField field = db->field[f];
571: /* copy then remove */
572: PetscCall(DMSwarmDataFieldCopyPoint(db->L - 1, field, index, field));
573: /* DMSwarmDataFieldZeroPoint(field,index); */
574: }
575: }
576: /* decrement size */
577: /* this will zero out an crap at the end of the list */
578: PetscCall(DMSwarmDataBucketRemovePoint(db));
579: PetscFunctionReturn(PETSC_SUCCESS);
580: }
582: /* copy x into y */
583: PetscErrorCode DMSwarmDataFieldCopyPoint(const PetscInt pid_x, const DMSwarmDataField field_x, const PetscInt pid_y, const DMSwarmDataField field_y)
584: {
585: PetscFunctionBegin;
586: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
587: /* check point is valid */
588: PetscCheck(pid_x >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be >= 0");
589: PetscCheck(pid_x < field_x->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be < %" PetscInt_FMT, field_x->L);
590: PetscCheck(pid_y >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be >= 0");
591: PetscCheck(pid_y < field_y->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be < %" PetscInt_FMT, field_y->L);
592: PetscCheck(field_y->atomic_size == field_x->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "atomic size must match");
593: #endif
594: PetscCall(PetscMemcpy(DMSWARM_DATAFIELD_point_access(field_y->data, pid_y, field_y->atomic_size), DMSWARM_DATAFIELD_point_access(field_x->data, pid_x, field_x->atomic_size), field_y->atomic_size));
595: PetscFunctionReturn(PETSC_SUCCESS);
596: }
598: /* zero only the datafield at this point */
599: PetscErrorCode DMSwarmDataFieldZeroPoint(const DMSwarmDataField field, const PetscInt index)
600: {
601: PetscFunctionBegin;
602: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
603: /* check point is valid */
604: PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
605: PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
606: #endif
607: PetscCall(PetscMemzero(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), field->atomic_size));
608: PetscFunctionReturn(PETSC_SUCCESS);
609: }
611: /* zero ALL data for this point */
612: PetscErrorCode DMSwarmDataBucketZeroPoint(const DMSwarmDataBucket db, const PetscInt index)
613: {
614: PetscInt f;
616: PetscFunctionBegin;
617: /* check point is valid */
618: PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
619: PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->allocated);
620: for (f = 0; f < db->nfields; ++f) {
621: DMSwarmDataField field = db->field[f];
622: PetscCall(DMSwarmDataFieldZeroPoint(field, index));
623: }
624: PetscFunctionReturn(PETSC_SUCCESS);
625: }
627: /* increment */
628: PetscErrorCode DMSwarmDataBucketAddPoint(DMSwarmDataBucket db)
629: {
630: PetscFunctionBegin;
631: PetscCall(DMSwarmDataBucketSetSizes(db, PetscMax(db->L, 0) + 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
632: PetscFunctionReturn(PETSC_SUCCESS);
633: }
635: /* decrement */
636: PetscErrorCode DMSwarmDataBucketRemovePoint(DMSwarmDataBucket db)
637: {
638: PetscFunctionBegin;
639: PetscCheck(db->L > 0, PetscObjectComm((PetscObject)db), PETSC_ERR_ARG_WRONG, "Swarm has no points to be removed");
640: PetscCall(DMSwarmDataBucketSetSizes(db, db->L - 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
641: PetscFunctionReturn(PETSC_SUCCESS);
642: }
644: /* Should be redone to user PetscViewer */
645: static PetscErrorCode DMSwarmDataBucketView_stdout(MPI_Comm comm, DMSwarmDataBucket db)
646: {
647: PetscInt f;
648: double memory_usage_total = 0.0;
650: PetscFunctionBegin;
651: PetscCall(PetscPrintf(comm, "DMSwarmDataBucketView: \n"));
652: PetscCall(PetscPrintf(comm, " L = %" PetscInt_FMT " \n", db->L));
653: PetscCall(PetscPrintf(comm, " buffer = %" PetscInt_FMT " \n", db->buffer));
654: PetscCall(PetscPrintf(comm, " allocated = %" PetscInt_FMT " \n", db->allocated));
655: PetscCall(PetscPrintf(comm, " nfields registered = %" PetscInt_FMT " \n", db->nfields));
657: for (f = 0; f < db->nfields; ++f) {
658: double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
659: memory_usage_total += memory_usage_f;
660: }
661: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &memory_usage_total, 1, MPI_DOUBLE, MPI_SUM, comm));
663: for (f = 0; f < db->nfields; ++f) {
664: double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
665: PetscCall(PetscPrintf(comm, " [%3" PetscInt_FMT "] %15s : Mem. usage = %1.2e (MB) [rank0]\n", f, db->field[f]->name, memory_usage_f));
666: PetscCall(PetscPrintf(comm, " blocksize = %" PetscInt_FMT " \n", db->field[f]->bs));
667: if (db->field[f]->bs != 1) {
668: PetscCall(PetscPrintf(comm, " atomic size = %zu [full block, bs=%" PetscInt_FMT "]\n", db->field[f]->atomic_size, db->field[f]->bs));
669: PetscCall(PetscPrintf(comm, " atomic size/item = %zu \n", (size_t)(db->field[f]->atomic_size / db->field[f]->bs)));
670: } else {
671: PetscCall(PetscPrintf(comm, " atomic size = %zu \n", db->field[f]->atomic_size));
672: }
673: }
674: PetscCall(PetscPrintf(comm, " Total mem. usage = %1.2e (MB) (collective)\n", memory_usage_total));
675: PetscFunctionReturn(PETSC_SUCCESS);
676: }
678: static PetscErrorCode DMSwarmDataBucketView_Seq(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
679: {
680: PetscFunctionBegin;
681: switch (type) {
682: case DATABUCKET_VIEW_STDOUT:
683: PetscCall(DMSwarmDataBucketView_stdout(PETSC_COMM_SELF, db));
684: break;
685: case DATABUCKET_VIEW_ASCII:
686: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for ascii output");
687: case DATABUCKET_VIEW_BINARY:
688: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for binary output");
689: case DATABUCKET_VIEW_HDF5:
690: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for HDF5 output");
691: default:
692: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer method requested");
693: }
694: PetscFunctionReturn(PETSC_SUCCESS);
695: }
697: static PetscErrorCode DMSwarmDataBucketView_MPI(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
698: {
699: PetscFunctionBegin;
700: switch (type) {
701: case DATABUCKET_VIEW_STDOUT:
702: PetscCall(DMSwarmDataBucketView_stdout(comm, db));
703: break;
704: case DATABUCKET_VIEW_ASCII:
705: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for ascii output");
706: case DATABUCKET_VIEW_BINARY:
707: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for binary output");
708: case DATABUCKET_VIEW_HDF5:
709: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for HDF5 output");
710: default:
711: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer method requested");
712: }
713: PetscFunctionReturn(PETSC_SUCCESS);
714: }
716: PetscErrorCode DMSwarmDataBucketView(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
717: {
718: PetscMPIInt size;
720: PetscFunctionBegin;
721: PetscCallMPI(MPI_Comm_size(comm, &size));
722: if (size == 1) {
723: PetscCall(DMSwarmDataBucketView_Seq(comm, db, filename, type));
724: } else {
725: PetscCall(DMSwarmDataBucketView_MPI(comm, db, filename, type));
726: }
727: PetscFunctionReturn(PETSC_SUCCESS);
728: }
730: PetscErrorCode DMSwarmDataBucketDuplicateFields(DMSwarmDataBucket dbA, DMSwarmDataBucket *dbB)
731: {
732: DMSwarmDataBucket db2;
733: PetscInt f;
735: PetscFunctionBegin;
736: PetscCall(DMSwarmDataBucketCreate(&db2));
737: /* copy contents from dbA into db2 */
738: for (f = 0; f < dbA->nfields; ++f) {
739: DMSwarmDataField field;
740: size_t atomic_size;
741: char *name;
743: field = dbA->field[f];
744: atomic_size = field->atomic_size;
745: name = field->name;
746: PetscCall(DMSwarmDataBucketRegisterField(db2, "DMSwarmDataBucketDuplicateFields", name, atomic_size, NULL));
747: }
748: PetscCall(DMSwarmDataBucketFinalize(db2));
749: PetscCall(DMSwarmDataBucketSetInitialSizes(db2, 0, 1000));
750: *dbB = db2;
751: PetscFunctionReturn(PETSC_SUCCESS);
752: }
754: /*
755: Insert points from db2 into db1
756: db1 <<== db2
757: */
758: PetscErrorCode DMSwarmDataBucketInsertValues(DMSwarmDataBucket db1, DMSwarmDataBucket db2)
759: {
760: PetscInt n_mp_points1, n_mp_points2;
761: PetscInt n_mp_points1_new;
763: PetscFunctionBegin;
764: PetscCall(DMSwarmDataBucketGetSizes(db1, &n_mp_points1, NULL, NULL));
765: PetscCall(DMSwarmDataBucketGetSizes(db2, &n_mp_points2, NULL, NULL));
766: n_mp_points1_new = n_mp_points1 + n_mp_points2;
767: PetscCall(DMSwarmDataBucketSetSizes(db1, n_mp_points1_new, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
768: for (PetscInt p = 0; p < n_mp_points2; ++p) {
769: /* db1 <<== db2 */
770: PetscCall(DMSwarmDataBucketCopyPoint(db2, p, db1, n_mp_points1 + p));
771: }
772: PetscFunctionReturn(PETSC_SUCCESS);
773: }
775: /* helpers for parallel send/recv */
776: PetscErrorCode DMSwarmDataBucketCreatePackedArray(DMSwarmDataBucket db, size_t *bytes, void **buf)
777: {
778: size_t sizeof_marker_contents;
779: void *buffer;
781: PetscFunctionBegin;
782: sizeof_marker_contents = 0;
783: for (PetscInt f = 0; f < db->nfields; ++f) {
784: DMSwarmDataField df = db->field[f];
785: sizeof_marker_contents += df->atomic_size;
786: }
787: PetscCall(PetscMalloc(sizeof_marker_contents, &buffer));
788: PetscCall(PetscMemzero(buffer, sizeof_marker_contents));
789: if (bytes) *bytes = sizeof_marker_contents;
790: if (buf) *buf = buffer;
791: PetscFunctionReturn(PETSC_SUCCESS);
792: }
794: PetscErrorCode DMSwarmDataBucketDestroyPackedArray(DMSwarmDataBucket db, void **buf)
795: {
796: PetscFunctionBegin;
797: if (buf) {
798: PetscCall(PetscFree(*buf));
799: *buf = NULL;
800: }
801: PetscFunctionReturn(PETSC_SUCCESS);
802: }
804: PetscErrorCode DMSwarmDataBucketFillPackedArray(DMSwarmDataBucket db, const PetscInt index, void *buf)
805: {
806: void *data, *data_p;
807: size_t asize, offset;
809: PetscFunctionBegin;
810: offset = 0;
811: for (PetscInt f = 0; f < db->nfields; ++f) {
812: DMSwarmDataField df = db->field[f];
814: asize = df->atomic_size;
815: data = df->data;
816: data_p = (void *)((char *)data + index * asize);
817: PetscCall(PetscMemcpy((void *)((char *)buf + offset), data_p, asize));
818: offset = offset + asize;
819: }
820: PetscFunctionReturn(PETSC_SUCCESS);
821: }
823: PetscErrorCode DMSwarmDataBucketInsertPackedArray(DMSwarmDataBucket db, const PetscInt idx, void *data)
824: {
825: void *data_p;
826: size_t offset;
828: PetscFunctionBegin;
829: offset = 0;
830: for (PetscInt f = 0; f < db->nfields; ++f) {
831: DMSwarmDataField df = db->field[f];
833: data_p = (void *)((char *)data + offset);
834: PetscCall(DMSwarmDataFieldInsertPoint(df, idx, data_p));
835: offset = offset + df->atomic_size;
836: }
837: PetscFunctionReturn(PETSC_SUCCESS);
838: }