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