Actual source code: data_bucket.c
1: #include "../src/dm/impls/swarm/data_bucket.h"
3: /* string helpers */
4: PetscErrorCode DMSwarmDataFieldStringInList(const char name[], const PetscInt N, const DMSwarmDataField gfield[], PetscBool *val)
5: {
6: PetscInt i;
8: PetscFunctionBegin;
9: *val = PETSC_FALSE;
10: for (i = 0; i < N; ++i) {
11: PetscBool flg;
12: PetscCall(PetscStrcmp(name, gfield[i]->name, &flg));
13: if (flg) {
14: *val = PETSC_TRUE;
15: PetscFunctionReturn(PETSC_SUCCESS);
16: }
17: }
18: PetscFunctionReturn(PETSC_SUCCESS);
19: }
21: PetscErrorCode DMSwarmDataFieldStringFindInList(const char name[], const PetscInt N, const DMSwarmDataField gfield[], PetscInt *index)
22: {
23: PetscInt i;
25: PetscFunctionBegin;
26: *index = -1;
27: for (i = 0; i < N; ++i) {
28: PetscBool flg;
29: PetscCall(PetscStrcmp(name, gfield[i]->name, &flg));
30: if (flg) {
31: *index = i;
32: PetscFunctionReturn(PETSC_SUCCESS);
33: }
34: }
35: PetscFunctionReturn(PETSC_SUCCESS);
36: }
38: PetscErrorCode DMSwarmDataFieldCreate(const char registration_function[], const char name[], const size_t size, const PetscInt L, DMSwarmDataField *DF)
39: {
40: DMSwarmDataField df;
42: PetscFunctionBegin;
43: PetscCall(PetscNew(&df));
44: PetscCall(PetscStrallocpy(registration_function, &df->registration_function));
45: PetscCall(PetscStrallocpy(name, &df->name));
46: df->atomic_size = size;
47: df->L = L;
48: df->bs = 1;
49: /* allocate something so we don't have to reallocate */
50: PetscCall(PetscMalloc(size * L, &df->data));
51: PetscCall(PetscMemzero(df->data, size * L));
52: *DF = df;
53: PetscFunctionReturn(PETSC_SUCCESS);
54: }
56: PetscErrorCode DMSwarmDataFieldDestroy(DMSwarmDataField *DF)
57: {
58: DMSwarmDataField df = *DF;
60: PetscFunctionBegin;
61: PetscCall(PetscFree(df->registration_function));
62: PetscCall(PetscFree(df->name));
63: PetscCall(PetscFree(df->data));
64: PetscCall(PetscFree(df));
65: *DF = NULL;
66: PetscFunctionReturn(PETSC_SUCCESS);
67: }
69: /* data bucket */
70: PetscErrorCode DMSwarmDataBucketCreate(DMSwarmDataBucket *DB)
71: {
72: DMSwarmDataBucket db;
74: PetscFunctionBegin;
75: PetscCall(PetscNew(&db));
77: db->finalised = PETSC_FALSE;
78: /* create empty spaces for fields */
79: db->L = -1;
80: db->buffer = 1;
81: db->allocated = 1;
82: db->nfields = 0;
83: PetscCall(PetscMalloc1(1, &db->field));
84: *DB = db;
85: PetscFunctionReturn(PETSC_SUCCESS);
86: }
88: PetscErrorCode DMSwarmDataBucketDestroy(DMSwarmDataBucket *DB)
89: {
90: DMSwarmDataBucket db = *DB;
91: PetscInt f;
93: PetscFunctionBegin;
94: /* release fields */
95: for (f = 0; f < db->nfields; ++f) PetscCall(DMSwarmDataFieldDestroy(&db->field[f]));
96: /* this will catch the initially allocated objects in the event that no fields are registered */
97: if (db->field != NULL) PetscCall(PetscFree(db->field));
98: PetscCall(PetscFree(db));
99: *DB = NULL;
100: PetscFunctionReturn(PETSC_SUCCESS);
101: }
103: PetscErrorCode DMSwarmDataBucketQueryForActiveFields(DMSwarmDataBucket db, PetscBool *any_active_fields)
104: {
105: PetscInt f;
107: PetscFunctionBegin;
108: *any_active_fields = PETSC_FALSE;
109: for (f = 0; f < db->nfields; ++f) {
110: if (db->field[f]->active) {
111: *any_active_fields = PETSC_TRUE;
112: PetscFunctionReturn(PETSC_SUCCESS);
113: }
114: }
115: PetscFunctionReturn(PETSC_SUCCESS);
116: }
118: PetscErrorCode DMSwarmDataBucketRegisterField(DMSwarmDataBucket db, const char registration_function[], const char field_name[], size_t atomic_size, DMSwarmDataField *_gfield)
119: {
120: PetscBool val;
121: DMSwarmDataField fp;
123: PetscFunctionBegin;
124: /* check we haven't finalised the registration of fields */
125: /*
126: if (db->finalised==PETSC_TRUE) {
127: printf("ERROR: DMSwarmDataBucketFinalize() has been called. Cannot register more fields\n");
128: ERROR();
129: }
130: */
131: /* check for repeated name */
132: PetscCall(DMSwarmDataFieldStringInList(field_name, db->nfields, (const DMSwarmDataField *)db->field, &val));
133: PetscCheck(val != PETSC_TRUE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field %s already exists. Cannot add same field twice", field_name);
134: /* create new space for data */
135: PetscCall(PetscRealloc(sizeof(DMSwarmDataField) * (db->nfields + 1), &db->field));
136: /* add field */
137: PetscCall(DMSwarmDataFieldCreate(registration_function, field_name, atomic_size, db->allocated, &fp));
138: db->field[db->nfields] = fp;
139: db->nfields++;
140: if (_gfield != NULL) *_gfield = fp;
141: PetscFunctionReturn(PETSC_SUCCESS);
142: }
144: /*
145: #define DMSwarmDataBucketRegisterField(db,name,size,k) {\
146: char *location;\
147: asprintf(&location,"Registered by %s() at line %d within file %s", __FUNCTION__, __LINE__, __FILE__);\
148: _DMSwarmDataBucketRegisterField( (db), location, (name), (size), (k));\
149: ierr = PetscFree(location);\
150: }
151: */
153: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldIdByName(DMSwarmDataBucket db, const char name[], PetscInt *idx)
154: {
155: PetscBool found;
157: PetscFunctionBegin;
158: *idx = -1;
159: PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, &found));
160: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot find DMSwarmDataField with name %s", name);
161: PetscCall(DMSwarmDataFieldStringFindInList(name, db->nfields, (const DMSwarmDataField *)db->field, idx));
162: PetscFunctionReturn(PETSC_SUCCESS);
163: }
165: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFieldByName(DMSwarmDataBucket db, const char name[], DMSwarmDataField *gfield)
166: {
167: PetscInt idx;
168: PetscBool found;
170: PetscFunctionBegin;
171: PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, &found));
172: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot find DMSwarmDataField with name %s", name);
173: PetscCall(DMSwarmDataFieldStringFindInList(name, db->nfields, (const DMSwarmDataField *)db->field, &idx));
174: *gfield = db->field[idx];
175: PetscFunctionReturn(PETSC_SUCCESS);
176: }
178: PetscErrorCode DMSwarmDataBucketQueryDMSwarmDataFieldByName(DMSwarmDataBucket db, const char name[], PetscBool *found)
179: {
180: PetscFunctionBegin;
181: *found = PETSC_FALSE;
182: PetscCall(DMSwarmDataFieldStringInList(name, db->nfields, (const DMSwarmDataField *)db->field, found));
183: PetscFunctionReturn(PETSC_SUCCESS);
184: }
186: PetscErrorCode DMSwarmDataBucketFinalize(DMSwarmDataBucket db)
187: {
188: PetscFunctionBegin;
189: db->finalised = PETSC_TRUE;
190: PetscFunctionReturn(PETSC_SUCCESS);
191: }
193: PetscErrorCode DMSwarmDataFieldGetNumEntries(DMSwarmDataField df, PetscInt *sum)
194: {
195: PetscFunctionBegin;
196: *sum = df->L;
197: PetscFunctionReturn(PETSC_SUCCESS);
198: }
200: PetscErrorCode DMSwarmDataFieldSetBlockSize(DMSwarmDataField df, PetscInt blocksize)
201: {
202: PetscFunctionBegin;
203: df->bs = blocksize;
204: PetscFunctionReturn(PETSC_SUCCESS);
205: }
207: PetscErrorCode DMSwarmDataFieldSetSize(DMSwarmDataField df, const PetscInt new_L)
208: {
209: PetscFunctionBegin;
210: PetscCheck(new_L >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot set size of DMSwarmDataField to be < 0");
211: if (new_L == df->L) PetscFunctionReturn(PETSC_SUCCESS);
212: if (new_L > df->L) {
213: PetscCall(PetscRealloc(df->atomic_size * (new_L), &df->data));
214: /* init new contents */
215: PetscCall(PetscMemzero((((char *)df->data) + df->L * df->atomic_size), (new_L - df->L) * df->atomic_size));
216: } else {
217: /* reallocate pointer list, add +1 in case new_L = 0 */
218: PetscCall(PetscRealloc(df->atomic_size * (new_L + 1), &df->data));
219: }
220: df->L = new_L;
221: PetscFunctionReturn(PETSC_SUCCESS);
222: }
224: PetscErrorCode DMSwarmDataFieldZeroBlock(DMSwarmDataField df, const PetscInt start, const PetscInt end)
225: {
226: PetscFunctionBegin;
227: PetscCheck(start <= end, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") > end(%" PetscInt_FMT ")", start, end);
228: PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if start(%" PetscInt_FMT ") < 0", start);
229: PetscCheck(end <= df->L, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot zero a block of entries if end(%" PetscInt_FMT ") >= array size(%" PetscInt_FMT ")", end, df->L);
230: PetscCall(PetscMemzero((((char *)df->data) + start * df->atomic_size), (end - start) * df->atomic_size));
231: PetscFunctionReturn(PETSC_SUCCESS);
232: }
234: /*
235: A negative buffer value will simply be ignored and the old buffer value will be used.
236: */
237: PetscErrorCode DMSwarmDataBucketSetSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
238: {
239: PetscInt current_allocated, new_used, new_unused, new_buffer, new_allocated, f;
240: PetscBool any_active_fields;
242: PetscFunctionBegin;
243: PetscCheck(db->finalised != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "You must call DMSwarmDataBucketFinalize() before DMSwarmDataBucketSetSizes()");
244: PetscCall(DMSwarmDataBucketQueryForActiveFields(db, &any_active_fields));
245: PetscCheck(!any_active_fields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot safely re-size as at least one DMSwarmDataField is currently being accessed");
247: current_allocated = db->allocated;
248: new_used = L;
249: new_unused = current_allocated - new_used;
250: new_buffer = db->buffer;
251: if (buffer >= 0) { /* update the buffer value */
252: new_buffer = buffer;
253: }
254: new_allocated = new_used + new_buffer;
255: /* action */
256: if (new_allocated > current_allocated) {
257: /* increase size to new_used + new_buffer */
258: for (f = 0; f < db->nfields; f++) PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
259: db->L = new_used;
260: db->buffer = new_buffer;
261: db->allocated = new_used + new_buffer;
262: } else {
263: if (new_unused > 2 * new_buffer) {
264: /* shrink array to new_used + new_buffer */
265: for (f = 0; f < db->nfields; ++f) PetscCall(DMSwarmDataFieldSetSize(db->field[f], new_allocated));
266: db->L = new_used;
267: db->buffer = new_buffer;
268: db->allocated = new_used + new_buffer;
269: } else {
270: db->L = new_used;
271: db->buffer = new_buffer;
272: }
273: }
274: /* zero all entries from db->L to db->allocated */
275: for (f = 0; f < db->nfields; ++f) {
276: DMSwarmDataField field = db->field[f];
277: PetscCall(DMSwarmDataFieldZeroBlock(field, db->L, db->allocated));
278: }
279: PetscFunctionReturn(PETSC_SUCCESS);
280: }
282: PetscErrorCode DMSwarmDataBucketSetInitialSizes(DMSwarmDataBucket db, const PetscInt L, const PetscInt buffer)
283: {
284: PetscInt f;
286: PetscFunctionBegin;
287: PetscCall(DMSwarmDataBucketSetSizes(db, L, buffer));
288: for (f = 0; f < db->nfields; ++f) {
289: DMSwarmDataField field = db->field[f];
290: PetscCall(DMSwarmDataFieldZeroBlock(field, 0, db->allocated));
291: }
292: PetscFunctionReturn(PETSC_SUCCESS);
293: }
295: PetscErrorCode DMSwarmDataBucketGetSizes(DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
296: {
297: PetscFunctionBegin;
298: if (L) *L = db->L;
299: if (buffer) *buffer = db->buffer;
300: if (allocated) *allocated = db->allocated;
301: PetscFunctionReturn(PETSC_SUCCESS);
302: }
304: PetscErrorCode DMSwarmDataBucketGetGlobalSizes(MPI_Comm comm, DMSwarmDataBucket db, PetscInt *L, PetscInt *buffer, PetscInt *allocated)
305: {
306: PetscFunctionBegin;
307: if (L) PetscCall(MPIU_Allreduce(&db->L, L, 1, MPIU_INT, MPI_SUM, comm));
308: if (buffer) PetscCall(MPIU_Allreduce(&db->buffer, buffer, 1, MPIU_INT, MPI_SUM, comm));
309: if (allocated) PetscCall(MPIU_Allreduce(&db->allocated, allocated, 1, MPIU_INT, MPI_SUM, comm));
310: PetscFunctionReturn(PETSC_SUCCESS);
311: }
313: PetscErrorCode DMSwarmDataBucketGetDMSwarmDataFields(DMSwarmDataBucket db, PetscInt *L, DMSwarmDataField *fields[])
314: {
315: PetscFunctionBegin;
316: if (L) *L = db->nfields;
317: if (fields) *fields = db->field;
318: PetscFunctionReturn(PETSC_SUCCESS);
319: }
321: PetscErrorCode DMSwarmDataFieldGetAccess(const DMSwarmDataField gfield)
322: {
323: PetscFunctionBegin;
324: PetscCheck(!gfield->active, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is already active. You must call DMSwarmDataFieldRestoreAccess()", gfield->name);
325: gfield->active = PETSC_TRUE;
326: PetscFunctionReturn(PETSC_SUCCESS);
327: }
329: PetscErrorCode DMSwarmDataFieldAccessPoint(const DMSwarmDataField gfield, const PetscInt pid, void **ctx_p)
330: {
331: PetscFunctionBegin;
332: *ctx_p = NULL;
333: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
334: /* debug mode */
335: /* check point is valid */
336: PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
337: PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
338: PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess() before point data can be retrivied", gfield->name);
339: #endif
340: *ctx_p = DMSWARM_DATAFIELD_point_access(gfield->data, pid, gfield->atomic_size);
341: PetscFunctionReturn(PETSC_SUCCESS);
342: }
344: PetscErrorCode DMSwarmDataFieldAccessPointOffset(const DMSwarmDataField gfield, const size_t offset, const PetscInt pid, void **ctx_p)
345: {
346: PetscFunctionBegin;
347: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
348: /* debug mode */
349: /* check point is valid */
350: /* PetscCheck(offset >= 0,PETSC_COMM_SELF,PETSC_ERR_USER,"offset must be >= 0");*/
351: /* Note compiler realizes this can never happen with an unsigned PetscInt */
352: PetscCheck(offset < gfield->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "offset must be < %zu", gfield->atomic_size);
353: /* check point is valid */
354: PetscCheck(pid >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
355: PetscCheck(pid < gfield->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, gfield->L);
356: PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess() before point data can be retrivied", gfield->name);
357: #endif
358: *ctx_p = DMSWARM_DATAFIELD_point_access_offset(gfield->data, pid, gfield->atomic_size, offset);
359: PetscFunctionReturn(PETSC_SUCCESS);
360: }
362: PetscErrorCode DMSwarmDataFieldRestoreAccess(DMSwarmDataField gfield)
363: {
364: PetscFunctionBegin;
365: PetscCheck(gfield->active != PETSC_FALSE, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" is not active. You must call DMSwarmDataFieldGetAccess()", gfield->name);
366: gfield->active = PETSC_FALSE;
367: PetscFunctionReturn(PETSC_SUCCESS);
368: }
370: PetscErrorCode DMSwarmDataFieldVerifyAccess(const DMSwarmDataField gfield, const size_t size)
371: {
372: PetscFunctionBegin;
373: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
374: PetscCheck(gfield->atomic_size == size, PETSC_COMM_SELF, PETSC_ERR_USER, "Field \"%s\" must be mapped to %zu bytes, your intended structure is %zu bytes in length.", gfield->name, gfield->atomic_size, size);
375: #endif
376: PetscFunctionReturn(PETSC_SUCCESS);
377: }
379: PetscErrorCode DMSwarmDataFieldGetAtomicSize(const DMSwarmDataField gfield, size_t *size)
380: {
381: PetscFunctionBegin;
382: if (size) *size = gfield->atomic_size;
383: PetscFunctionReturn(PETSC_SUCCESS);
384: }
386: PetscErrorCode DMSwarmDataFieldGetEntries(const DMSwarmDataField gfield, void **data)
387: {
388: PetscFunctionBegin;
389: if (data) *data = gfield->data;
390: PetscFunctionReturn(PETSC_SUCCESS);
391: }
393: PetscErrorCode DMSwarmDataFieldRestoreEntries(const DMSwarmDataField gfield, void **data)
394: {
395: PetscFunctionBegin;
396: if (data) *data = NULL;
397: PetscFunctionReturn(PETSC_SUCCESS);
398: }
400: /* y = x */
401: PetscErrorCode DMSwarmDataBucketCopyPoint(const DMSwarmDataBucket xb, const PetscInt pid_x, const DMSwarmDataBucket yb, const PetscInt pid_y)
402: {
403: PetscInt f;
405: PetscFunctionBegin;
406: for (f = 0; f < xb->nfields; ++f) {
407: void *dest;
408: void *src;
410: PetscCall(DMSwarmDataFieldGetAccess(xb->field[f]));
411: if (xb != yb) PetscCall(DMSwarmDataFieldGetAccess(yb->field[f]));
412: PetscCall(DMSwarmDataFieldAccessPoint(xb->field[f], pid_x, &src));
413: PetscCall(DMSwarmDataFieldAccessPoint(yb->field[f], pid_y, &dest));
414: PetscCall(PetscMemcpy(dest, src, xb->field[f]->atomic_size));
415: PetscCall(DMSwarmDataFieldRestoreAccess(xb->field[f]));
416: if (xb != yb) PetscCall(DMSwarmDataFieldRestoreAccess(yb->field[f]));
417: }
418: PetscFunctionReturn(PETSC_SUCCESS);
419: }
421: PetscErrorCode DMSwarmDataBucketCreateFromSubset(DMSwarmDataBucket DBIn, const PetscInt N, const PetscInt list[], DMSwarmDataBucket *DB)
422: {
423: PetscInt nfields;
424: DMSwarmDataField *fields;
425: PetscInt f, L, buffer, allocated, p;
427: PetscFunctionBegin;
428: PetscCall(DMSwarmDataBucketCreate(DB));
429: /* copy contents of DBIn */
430: PetscCall(DMSwarmDataBucketGetDMSwarmDataFields(DBIn, &nfields, &fields));
431: PetscCall(DMSwarmDataBucketGetSizes(DBIn, &L, &buffer, &allocated));
432: for (f = 0; f < nfields; ++f) PetscCall(DMSwarmDataBucketRegisterField(*DB, "DMSwarmDataBucketCreateFromSubset", fields[f]->name, fields[f]->atomic_size, NULL));
433: PetscCall(DMSwarmDataBucketFinalize(*DB));
434: PetscCall(DMSwarmDataBucketSetSizes(*DB, L, buffer));
435: /* now copy the desired guys from DBIn => DB */
436: for (p = 0; p < N; ++p) PetscCall(DMSwarmDataBucketCopyPoint(DBIn, list[p], *DB, list[p]));
437: PetscFunctionReturn(PETSC_SUCCESS);
438: }
440: /* insert into an existing location */
441: PetscErrorCode DMSwarmDataFieldInsertPoint(const DMSwarmDataField field, const PetscInt index, const void *ctx)
442: {
443: PetscFunctionBegin;
444: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
445: /* check point is valid */
446: PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
447: PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
448: #endif
449: PetscCall(PetscMemcpy(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), ctx, field->atomic_size));
450: PetscFunctionReturn(PETSC_SUCCESS);
451: }
453: /* remove data at index - replace with last point */
454: PetscErrorCode DMSwarmDataBucketRemovePointAtIndex(const DMSwarmDataBucket db, const PetscInt index)
455: {
456: PetscInt f;
457: PetscBool any_active_fields;
459: PetscFunctionBegin;
460: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
461: /* check point is valid */
462: PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
463: PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->L + db->buffer);
464: #endif
465: PetscCall(DMSwarmDataBucketQueryForActiveFields(db, &any_active_fields));
466: PetscCheck(!any_active_fields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot safely remove point as at least one DMSwarmDataField is currently being accessed");
467: if (index >= db->L) { /* this point is not in the list - no need to error, but I will anyway */
468: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "You should not be trying to remove point at index=%" PetscInt_FMT " since it's < db->L = %" PetscInt_FMT, index, db->L);
469: }
470: if (index != db->L - 1) { /* not last point in list */
471: for (f = 0; f < db->nfields; ++f) {
472: DMSwarmDataField field = db->field[f];
474: /* copy then remove */
475: PetscCall(DMSwarmDataFieldCopyPoint(db->L - 1, field, index, field));
476: /* DMSwarmDataFieldZeroPoint(field,index); */
477: }
478: }
479: /* decrement size */
480: /* this will zero out an crap at the end of the list */
481: PetscCall(DMSwarmDataBucketRemovePoint(db));
482: PetscFunctionReturn(PETSC_SUCCESS);
483: }
485: /* copy x into y */
486: PetscErrorCode DMSwarmDataFieldCopyPoint(const PetscInt pid_x, const DMSwarmDataField field_x, const PetscInt pid_y, const DMSwarmDataField field_y)
487: {
488: PetscFunctionBegin;
489: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
490: /* check point is valid */
491: PetscCheck(pid_x >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be >= 0");
492: PetscCheck(pid_x < field_x->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(IN) index must be < %" PetscInt_FMT, field_x->L);
493: PetscCheck(pid_y >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be >= 0");
494: PetscCheck(pid_y < field_y->L, PETSC_COMM_SELF, PETSC_ERR_USER, "(OUT) index must be < %" PetscInt_FMT, field_y->L);
495: PetscCheck(field_y->atomic_size == field_x->atomic_size, PETSC_COMM_SELF, PETSC_ERR_USER, "atomic size must match");
496: #endif
497: PetscCall(PetscMemcpy(DMSWARM_DATAFIELD_point_access(field_y->data, pid_y, field_y->atomic_size), DMSWARM_DATAFIELD_point_access(field_x->data, pid_x, field_x->atomic_size), field_y->atomic_size));
498: PetscFunctionReturn(PETSC_SUCCESS);
499: }
501: /* zero only the datafield at this point */
502: PetscErrorCode DMSwarmDataFieldZeroPoint(const DMSwarmDataField field, const PetscInt index)
503: {
504: PetscFunctionBegin;
505: #if defined(DMSWARM_DATAFIELD_POINT_ACCESS_GUARD)
506: /* check point is valid */
507: PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
508: PetscCheck(index < field->L, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, field->L);
509: #endif
510: PetscCall(PetscMemzero(DMSWARM_DATAFIELD_point_access(field->data, index, field->atomic_size), field->atomic_size));
511: PetscFunctionReturn(PETSC_SUCCESS);
512: }
514: /* zero ALL data for this point */
515: PetscErrorCode DMSwarmDataBucketZeroPoint(const DMSwarmDataBucket db, const PetscInt index)
516: {
517: PetscInt f;
519: PetscFunctionBegin;
520: /* check point is valid */
521: PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be >= 0");
522: PetscCheck(index < db->allocated, PETSC_COMM_SELF, PETSC_ERR_USER, "index must be < %" PetscInt_FMT, db->allocated);
523: for (f = 0; f < db->nfields; ++f) {
524: DMSwarmDataField field = db->field[f];
525: PetscCall(DMSwarmDataFieldZeroPoint(field, index));
526: }
527: PetscFunctionReturn(PETSC_SUCCESS);
528: }
530: /* increment */
531: PetscErrorCode DMSwarmDataBucketAddPoint(DMSwarmDataBucket db)
532: {
533: PetscFunctionBegin;
534: PetscCall(DMSwarmDataBucketSetSizes(db, db->L + 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
535: PetscFunctionReturn(PETSC_SUCCESS);
536: }
538: /* decrement */
539: PetscErrorCode DMSwarmDataBucketRemovePoint(DMSwarmDataBucket db)
540: {
541: PetscFunctionBegin;
542: PetscCall(DMSwarmDataBucketSetSizes(db, db->L - 1, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
543: PetscFunctionReturn(PETSC_SUCCESS);
544: }
546: /* Should be redone to user PetscViewer */
547: static PetscErrorCode DMSwarmDataBucketView_stdout(MPI_Comm comm, DMSwarmDataBucket db)
548: {
549: PetscInt f;
550: double memory_usage_total, memory_usage_total_local = 0.0;
552: PetscFunctionBegin;
553: PetscCall(PetscPrintf(comm, "DMSwarmDataBucketView: \n"));
554: PetscCall(PetscPrintf(comm, " L = %" PetscInt_FMT " \n", db->L));
555: PetscCall(PetscPrintf(comm, " buffer = %" PetscInt_FMT " \n", db->buffer));
556: PetscCall(PetscPrintf(comm, " allocated = %" PetscInt_FMT " \n", db->allocated));
557: PetscCall(PetscPrintf(comm, " nfields registered = %" PetscInt_FMT " \n", db->nfields));
559: for (f = 0; f < db->nfields; ++f) {
560: double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
561: memory_usage_total_local += memory_usage_f;
562: }
563: PetscCallMPI(MPI_Allreduce(&memory_usage_total_local, &memory_usage_total, 1, MPI_DOUBLE, MPI_SUM, comm));
565: for (f = 0; f < db->nfields; ++f) {
566: double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
567: PetscCall(PetscPrintf(comm, " [%3" PetscInt_FMT "] %15s : Mem. usage = %1.2e (MB) [rank0]\n", f, db->field[f]->name, memory_usage_f));
568: PetscCall(PetscPrintf(comm, " blocksize = %" PetscInt_FMT " \n", db->field[f]->bs));
569: if (db->field[f]->bs != 1) {
570: PetscCall(PetscPrintf(comm, " atomic size = %zu [full block, bs=%" PetscInt_FMT "]\n", db->field[f]->atomic_size, db->field[f]->bs));
571: PetscCall(PetscPrintf(comm, " atomic size/item = %zu \n", (size_t)(db->field[f]->atomic_size / db->field[f]->bs)));
572: } else {
573: PetscCall(PetscPrintf(comm, " atomic size = %zu \n", db->field[f]->atomic_size));
574: }
575: }
576: PetscCall(PetscPrintf(comm, " Total mem. usage = %1.2e (MB) (collective)\n", memory_usage_total));
577: PetscFunctionReturn(PETSC_SUCCESS);
578: }
580: static PetscErrorCode DMSwarmDataBucketView_Seq(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
581: {
582: PetscFunctionBegin;
583: switch (type) {
584: case DATABUCKET_VIEW_STDOUT:
585: PetscCall(DMSwarmDataBucketView_stdout(PETSC_COMM_SELF, db));
586: break;
587: case DATABUCKET_VIEW_ASCII:
588: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for ascii output");
589: case DATABUCKET_VIEW_BINARY:
590: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for binary output");
591: case DATABUCKET_VIEW_HDF5:
592: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for HDF5 output");
593: default:
594: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer method requested");
595: }
596: PetscFunctionReturn(PETSC_SUCCESS);
597: }
599: static PetscErrorCode DMSwarmDataBucketView_MPI(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
600: {
601: PetscFunctionBegin;
602: switch (type) {
603: case DATABUCKET_VIEW_STDOUT:
604: PetscCall(DMSwarmDataBucketView_stdout(comm, db));
605: break;
606: case DATABUCKET_VIEW_ASCII:
607: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for ascii output");
608: case DATABUCKET_VIEW_BINARY:
609: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for binary output");
610: case DATABUCKET_VIEW_HDF5:
611: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for HDF5 output");
612: default:
613: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer method requested");
614: }
615: PetscFunctionReturn(PETSC_SUCCESS);
616: }
618: PetscErrorCode DMSwarmDataBucketView(MPI_Comm comm, DMSwarmDataBucket db, const char filename[], DMSwarmDataBucketViewType type)
619: {
620: PetscMPIInt size;
622: PetscFunctionBegin;
623: PetscCallMPI(MPI_Comm_size(comm, &size));
624: if (size == 1) {
625: PetscCall(DMSwarmDataBucketView_Seq(comm, db, filename, type));
626: } else {
627: PetscCall(DMSwarmDataBucketView_MPI(comm, db, filename, type));
628: }
629: PetscFunctionReturn(PETSC_SUCCESS);
630: }
632: PetscErrorCode DMSwarmDataBucketDuplicateFields(DMSwarmDataBucket dbA, DMSwarmDataBucket *dbB)
633: {
634: DMSwarmDataBucket db2;
635: PetscInt f;
637: PetscFunctionBegin;
638: PetscCall(DMSwarmDataBucketCreate(&db2));
639: /* copy contents from dbA into db2 */
640: for (f = 0; f < dbA->nfields; ++f) {
641: DMSwarmDataField field;
642: size_t atomic_size;
643: char *name;
645: field = dbA->field[f];
646: atomic_size = field->atomic_size;
647: name = field->name;
648: PetscCall(DMSwarmDataBucketRegisterField(db2, "DMSwarmDataBucketDuplicateFields", name, atomic_size, NULL));
649: }
650: PetscCall(DMSwarmDataBucketFinalize(db2));
651: PetscCall(DMSwarmDataBucketSetInitialSizes(db2, 0, 1000));
652: *dbB = db2;
653: PetscFunctionReturn(PETSC_SUCCESS);
654: }
656: /*
657: Insert points from db2 into db1
658: db1 <<== db2
659: */
660: PetscErrorCode DMSwarmDataBucketInsertValues(DMSwarmDataBucket db1, DMSwarmDataBucket db2)
661: {
662: PetscInt n_mp_points1, n_mp_points2;
663: PetscInt n_mp_points1_new, p;
665: PetscFunctionBegin;
666: PetscCall(DMSwarmDataBucketGetSizes(db1, &n_mp_points1, NULL, NULL));
667: PetscCall(DMSwarmDataBucketGetSizes(db2, &n_mp_points2, NULL, NULL));
668: n_mp_points1_new = n_mp_points1 + n_mp_points2;
669: PetscCall(DMSwarmDataBucketSetSizes(db1, n_mp_points1_new, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
670: for (p = 0; p < n_mp_points2; ++p) {
671: /* db1 <<== db2 */
672: PetscCall(DMSwarmDataBucketCopyPoint(db2, p, db1, (n_mp_points1 + p)));
673: }
674: PetscFunctionReturn(PETSC_SUCCESS);
675: }
677: /* helpers for parallel send/recv */
678: PetscErrorCode DMSwarmDataBucketCreatePackedArray(DMSwarmDataBucket db, size_t *bytes, void **buf)
679: {
680: PetscInt f;
681: size_t sizeof_marker_contents;
682: void *buffer;
684: PetscFunctionBegin;
685: sizeof_marker_contents = 0;
686: for (f = 0; f < db->nfields; ++f) {
687: DMSwarmDataField df = db->field[f];
688: sizeof_marker_contents += df->atomic_size;
689: }
690: PetscCall(PetscMalloc(sizeof_marker_contents, &buffer));
691: PetscCall(PetscMemzero(buffer, sizeof_marker_contents));
692: if (bytes) *bytes = sizeof_marker_contents;
693: if (buf) *buf = buffer;
694: PetscFunctionReturn(PETSC_SUCCESS);
695: }
697: PetscErrorCode DMSwarmDataBucketDestroyPackedArray(DMSwarmDataBucket db, void **buf)
698: {
699: PetscFunctionBegin;
700: if (buf) {
701: PetscCall(PetscFree(*buf));
702: *buf = NULL;
703: }
704: PetscFunctionReturn(PETSC_SUCCESS);
705: }
707: PetscErrorCode DMSwarmDataBucketFillPackedArray(DMSwarmDataBucket db, const PetscInt index, void *buf)
708: {
709: PetscInt f;
710: void *data, *data_p;
711: size_t asize, offset;
713: PetscFunctionBegin;
714: offset = 0;
715: for (f = 0; f < db->nfields; ++f) {
716: DMSwarmDataField df = db->field[f];
718: asize = df->atomic_size;
719: data = (void *)(df->data);
720: data_p = (void *)((char *)data + index * asize);
721: PetscCall(PetscMemcpy((void *)((char *)buf + offset), data_p, asize));
722: offset = offset + asize;
723: }
724: PetscFunctionReturn(PETSC_SUCCESS);
725: }
727: PetscErrorCode DMSwarmDataBucketInsertPackedArray(DMSwarmDataBucket db, const PetscInt idx, void *data)
728: {
729: PetscInt f;
730: void *data_p;
731: size_t offset;
733: PetscFunctionBegin;
734: offset = 0;
735: for (f = 0; f < db->nfields; ++f) {
736: DMSwarmDataField df = db->field[f];
738: data_p = (void *)((char *)data + offset);
739: PetscCall(DMSwarmDataFieldInsertPoint(df, idx, (void *)data_p));
740: offset = offset + df->atomic_size;
741: }
742: PetscFunctionReturn(PETSC_SUCCESS);
743: }