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: }