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