xref: /petsc/src/dm/impls/swarm/data_bucket.c (revision 390e1bf27627d887df99a9f4d0d0ad68037f55ec)
1 
2 #include "data_bucket.h"
3 
4 /* string helpers */
5 PetscErrorCode StringInList(const char name[],const PetscInt N,const DataField gfield[],PetscBool *val)
6 {
7   PetscInt       i;
8   PetscErrorCode ierr;
9 
10   PetscFunctionBegin;
11   *val = PETSC_FALSE;
12   for (i = 0; i < N; ++i) {
13     PetscBool flg;
14     ierr = PetscStrcmp(name, gfield[i]->name, &flg);CHKERRQ(ierr);
15     if (flg) {
16       *val = PETSC_TRUE;
17       PetscFunctionReturn(0);
18     }
19   }
20   PetscFunctionReturn(0);
21 }
22 
23 PetscErrorCode StringFindInList(const char name[],const PetscInt N,const DataField gfield[],PetscInt *index)
24 {
25   PetscInt       i;
26   PetscErrorCode ierr;
27 
28   PetscFunctionBegin;
29   *index = -1;
30   for (i = 0; i < N; ++i) {
31     PetscBool flg;
32     ierr = PetscStrcmp(name, gfield[i]->name, &flg);CHKERRQ(ierr);
33     if (flg) {
34       *index = i;
35       PetscFunctionReturn(0);
36     }
37   }
38   PetscFunctionReturn(0);
39 }
40 
41 PetscErrorCode DataFieldCreate(const char registeration_function[],const char name[],const size_t size,const PetscInt L,DataField *DF)
42 {
43   DataField      df;
44   PetscErrorCode ierr;
45 
46   PetscFunctionBegin;
47   ierr = PetscMalloc(sizeof(struct _p_DataField), &df);CHKERRQ(ierr);
48   ierr = PetscMemzero(df, sizeof(struct _p_DataField));CHKERRQ(ierr);
49   ierr = PetscStrallocpy(registeration_function, &df->registeration_function);CHKERRQ(ierr);
50   ierr = PetscStrallocpy(name, &df->name);CHKERRQ(ierr);
51   df->atomic_size = size;
52   df->L  = L;
53   df->bs = 1;
54   /* allocate something so we don't have to reallocate */
55   ierr = PetscMalloc(size * L, &df->data);CHKERRQ(ierr);
56   ierr = PetscMemzero(df->data, size * L);CHKERRQ(ierr);
57   *DF = df;
58   PetscFunctionReturn(0);
59 }
60 
61 PetscErrorCode DataFieldDestroy(DataField *DF)
62 {
63   DataField      df = *DF;
64   PetscErrorCode ierr;
65 
66   PetscFunctionBegin;
67   ierr = PetscFree(df->registeration_function);CHKERRQ(ierr);
68   ierr = PetscFree(df->name);CHKERRQ(ierr);
69   ierr = PetscFree(df->data);CHKERRQ(ierr);
70   ierr = PetscFree(df);CHKERRQ(ierr);
71   *DF  = NULL;
72   PetscFunctionReturn(0);
73 }
74 
75 /* data bucket */
76 PetscErrorCode DataBucketCreate(DataBucket *DB)
77 {
78   DataBucket     db;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   ierr = PetscMalloc(sizeof(struct _p_DataBucket), &db);CHKERRQ(ierr);
83   ierr = PetscMemzero(db, sizeof(struct _p_DataBucket));CHKERRQ(ierr);
84 
85   db->finalised = PETSC_FALSE;
86   /* create empty spaces for fields */
87   db->L         = -1;
88   db->buffer    = 1;
89   db->allocated = 1;
90   db->nfields   = 0;
91   ierr = PetscMalloc1(1, &db->field);CHKERRQ(ierr);
92   *DB  = db;
93   PetscFunctionReturn(0);
94 }
95 
96 PetscErrorCode DataBucketDestroy(DataBucket *DB)
97 {
98   DataBucket     db = *DB;
99   PetscInt       f;
100   PetscErrorCode ierr;
101 
102   PetscFunctionBegin;
103   /* release fields */
104   for (f = 0; f < db->nfields; ++f) {
105     ierr = DataFieldDestroy(&db->field[f]);CHKERRQ(ierr);
106   }
107   /* this will catch the initially allocated objects in the event that no fields are registered */
108   if (db->field != NULL) {
109     ierr = PetscFree(db->field);CHKERRQ(ierr);
110   }
111   ierr = PetscFree(db);CHKERRQ(ierr);
112   *DB = NULL;
113   PetscFunctionReturn(0);
114 }
115 
116 PetscErrorCode DataBucketQueryForActiveFields(DataBucket db,PetscBool *any_active_fields)
117 {
118   PetscInt f;
119 
120   PetscFunctionBegin;
121   *any_active_fields = PETSC_FALSE;
122   for (f = 0; f < db->nfields; ++f) {
123     if (db->field[f]->active) {
124       *any_active_fields = PETSC_TRUE;
125       PetscFunctionReturn(0);
126     }
127   }
128   PetscFunctionReturn(0);
129 }
130 
131 PetscErrorCode DataBucketRegisterField(
132                               DataBucket db,
133                               const char registeration_function[],
134                               const char field_name[],
135                               size_t atomic_size, DataField *_gfield)
136 {
137   PetscBool val;
138   DataField fp;
139   PetscErrorCode ierr;
140 
141   PetscFunctionBegin;
142 	/* check we haven't finalised the registration of fields */
143 	/*
144    if(db->finalised==PETSC_TRUE) {
145    printf("ERROR: DataBucketFinalize() has been called. Cannot register more fields\n");
146    ERROR();
147    }
148    */
149   /* check for repeated name */
150   ierr = StringInList(field_name, db->nfields, (const DataField*) db->field, &val);CHKERRQ(ierr);
151   if (val == PETSC_TRUE) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Field %s already exists. Cannot add same field twice",field_name);
152   /* create new space for data */
153   ierr = PetscRealloc(sizeof(DataField)*(db->nfields+1), &db->field);CHKERRQ(ierr);
154   /* add field */
155   ierr = DataFieldCreate(registeration_function, field_name, atomic_size, db->allocated, &fp);CHKERRQ(ierr);
156   db->field[db->nfields] = fp;
157   db->nfields++;
158   if (_gfield != NULL) {
159     *_gfield = fp;
160   }
161   PetscFunctionReturn(0);
162 }
163 
164 /*
165  #define DataBucketRegisterField(db,name,size,k) {\
166  char *location;\
167  asprintf(&location,"Registered by %s() at line %d within file %s", __FUNCTION__, __LINE__, __FILE__);\
168  _DataBucketRegisterField( (db), location, (name), (size), (k) );\
169  ierr = PetscFree(location);\
170  }
171  */
172 
173 PetscErrorCode DataBucketGetDataFieldByName(DataBucket db,const char name[],DataField *gfield)
174 {
175   PetscInt       idx;
176   PetscBool      found;
177   PetscErrorCode ierr;
178 
179   PetscFunctionBegin;
180   ierr = StringInList(name,db->nfields,(const DataField*)db->field,&found);CHKERRQ(ierr);
181   if (!found) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot find DataField with name %s",name);
182   ierr = StringFindInList(name,db->nfields,(const DataField*)db->field,&idx);CHKERRQ(ierr);
183   *gfield = db->field[idx];
184   PetscFunctionReturn(0);
185 }
186 
187 PetscErrorCode DataBucketQueryDataFieldByName(DataBucket db,const char name[],PetscBool *found)
188 {
189   PetscErrorCode ierr;
190 
191   PetscFunctionBegin;
192   *found = PETSC_FALSE;
193   ierr = StringInList(name,db->nfields,(const DataField*)db->field,found);CHKERRQ(ierr);
194   PetscFunctionReturn(0);
195 }
196 
197 PetscErrorCode DataBucketFinalize(DataBucket db)
198 {
199   PetscFunctionBegin;
200   db->finalised = PETSC_TRUE;
201   PetscFunctionReturn(0);
202 }
203 
204 PetscErrorCode DataFieldGetNumEntries(DataField df,PetscInt *sum)
205 {
206   PetscFunctionBegin;
207   *sum = df->L;
208   PetscFunctionReturn(0);
209 }
210 
211 PetscErrorCode DataFieldSetBlockSize(DataField df,PetscInt blocksize)
212 {
213   PetscFunctionBegin;
214   df->bs = blocksize;
215   PetscFunctionReturn(0);
216 }
217 
218 PetscErrorCode DataFieldSetSize(DataField df,const PetscInt new_L)
219 {
220   PetscErrorCode ierr;
221 
222   PetscFunctionBegin;
223   if (new_L <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot set size of DataField to be <= 0");
224   if (new_L == df->L) PetscFunctionReturn(0);
225   if (new_L > df->L) {
226     ierr = PetscRealloc(df->atomic_size * (new_L), &df->data);CHKERRQ(ierr);
227     /* init new contents */
228     ierr = PetscMemzero(( ((char*)df->data)+df->L*df->atomic_size), (new_L-df->L)*df->atomic_size);CHKERRQ(ierr);
229   } else {
230     /* reallocate pointer list, add +1 in case new_L = 0 */
231     ierr = PetscRealloc(df->atomic_size * (new_L+1), &df->data);CHKERRQ(ierr);
232   }
233   df->L = new_L;
234   PetscFunctionReturn(0);
235 }
236 
237 PetscErrorCode DataFieldZeroBlock(DataField df,const PetscInt start,const PetscInt end)
238 {
239   PetscErrorCode ierr;
240 
241   PetscFunctionBegin;
242   if (start > end) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot zero a block of entries if start(%D) > end(%D)",start,end);
243   if (start < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot zero a block of entries if start(%D) < 0",start);
244   if (end > df->L) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot zero a block of entries if end(%D) >= array size(%D)",end,df->L);
245   ierr = PetscMemzero((((char*)df->data)+start*df->atomic_size), (end-start)*df->atomic_size);CHKERRQ(ierr);
246   PetscFunctionReturn(0);
247 }
248 
249 /*
250  A negative buffer value will simply be ignored and the old buffer value will be used.
251  */
252 PetscErrorCode DataBucketSetSizes(DataBucket db,const PetscInt L,const PetscInt buffer)
253 {
254   PetscInt       current_allocated,new_used,new_unused,new_buffer,new_allocated,f;
255   PetscBool      any_active_fields;
256   PetscErrorCode ierr;
257 
258   PetscFunctionBegin;
259   if (db->finalised == PETSC_FALSE) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"You must call DataBucketFinalize() before DataBucketSetSizes()");
260   ierr = DataBucketQueryForActiveFields(db,&any_active_fields);CHKERRQ(ierr);
261   if (any_active_fields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot safely re-size as at least one DataField is currently being accessed");
262 
263   current_allocated = db->allocated;
264   new_used   = L;
265   new_unused = current_allocated - new_used;
266   new_buffer = db->buffer;
267   if (buffer >= 0) { /* update the buffer value */
268     new_buffer = buffer;
269   }
270   new_allocated = new_used + new_buffer;
271   /* action */
272   if (new_allocated > current_allocated) {
273     /* increase size to new_used + new_buffer */
274     for (f=0; f<db->nfields; f++) {
275       ierr = DataFieldSetSize(db->field[f], new_allocated);CHKERRQ(ierr);
276     }
277     db->L         = new_used;
278     db->buffer    = new_buffer;
279     db->allocated = new_used + new_buffer;
280   } else {
281     if (new_unused > 2 * new_buffer) {
282       /* shrink array to new_used + new_buffer */
283       for (f = 0; f < db->nfields; ++f) {
284         ierr = DataFieldSetSize(db->field[f], new_allocated);CHKERRQ(ierr);
285       }
286       db->L         = new_used;
287       db->buffer    = new_buffer;
288       db->allocated = new_used + new_buffer;
289     } else {
290       db->L      = new_used;
291       db->buffer = new_buffer;
292     }
293   }
294   /* zero all entries from db->L to db->allocated */
295   for (f = 0; f < db->nfields; ++f) {
296     DataField field = db->field[f];
297     ierr = DataFieldZeroBlock(field, db->L,db->allocated);CHKERRQ(ierr);
298   }
299   PetscFunctionReturn(0);
300 }
301 
302 PetscErrorCode DataBucketSetInitialSizes(DataBucket db,const PetscInt L,const PetscInt buffer)
303 {
304   PetscInt       f;
305   PetscErrorCode ierr;
306 
307   PetscFunctionBegin;
308   ierr = DataBucketSetSizes(db,L,buffer);CHKERRQ(ierr);
309   for (f = 0; f < db->nfields; ++f) {
310     DataField field = db->field[f];
311     ierr = DataFieldZeroBlock(field,0,db->allocated);CHKERRQ(ierr);
312   }
313   PetscFunctionReturn(0);
314 }
315 
316 PetscErrorCode DataBucketGetSizes(DataBucket db,PetscInt *L,PetscInt *buffer,PetscInt *allocated)
317 {
318   PetscFunctionBegin;
319   if (L) {*L = db->L;}
320   if (buffer) {*buffer = db->buffer;}
321   if (allocated) {*allocated = db->allocated;}
322   PetscFunctionReturn(0);
323 }
324 
325 PetscErrorCode DataBucketGetGlobalSizes(MPI_Comm comm,DataBucket db,PetscInt *L,PetscInt *buffer,PetscInt *allocated)
326 {
327   PetscInt _L,_buffer,_allocated;
328   PetscInt ierr;
329 
330   PetscFunctionBegin;
331   _L = db->L;
332   _buffer = db->buffer;
333   _allocated = db->allocated;
334 
335   if (L) {         ierr = MPI_Allreduce(&_L,L,1,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr); }
336   if (buffer) {    ierr = MPI_Allreduce(&_buffer,buffer,1,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr); }
337   if (allocated) { ierr = MPI_Allreduce(&_allocated,allocated,1,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr); }
338   PetscFunctionReturn(0);
339 }
340 
341 PetscErrorCode DataBucketGetDataFields(DataBucket db,PetscInt *L,DataField *fields[])
342 {
343   PetscFunctionBegin;
344   if (L)      {*L      = db->nfields;}
345   if (fields) {*fields = db->field;}
346   PetscFunctionReturn(0);
347 }
348 
349 PetscErrorCode DataFieldGetAccess(const DataField gfield)
350 {
351   PetscFunctionBegin;
352   if (gfield->active) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Field \"%s\" is already active. You must call DataFieldRestoreAccess()",gfield->name);
353   gfield->active = PETSC_TRUE;
354   PetscFunctionReturn(0);
355 }
356 
357 PetscErrorCode DataFieldAccessPoint(const DataField gfield,const PetscInt pid,void **ctx_p)
358 {
359   PetscFunctionBegin;
360   *ctx_p = NULL;
361 #ifdef DATAFIELD_POINT_ACCESS_GUARD
362   /* debug mode */
363   /* check point is valid */
364   if (pid < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be >= 0");
365   if (pid >= gfield->L) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be < %D",gfield->L);
366   if (gfield->active == PETSC_FALSE) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Field \"%s\" is not active. You must call DataFieldGetAccess() before point data can be retrivied",gfield->name);
367 #endif
368   *ctx_p = __DATATFIELD_point_access(gfield->data,pid,gfield->atomic_size);
369   PetscFunctionReturn(0);
370 }
371 
372 PetscErrorCode DataFieldAccessPointOffset(const DataField gfield,const size_t offset,const PetscInt pid,void **ctx_p)
373 {
374   PetscFunctionBegin;
375 #ifdef DATAFIELD_POINT_ACCESS_GUARD
376   /* debug mode */
377   /* check point is valid */
378   /* if( offset < 0 ) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"offset must be >= 0");*/
379   /* Note compiler realizes this can never happen with an unsigned PetscInt */
380   if (offset >= gfield->atomic_size) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"offset must be < %zu",gfield->atomic_size);
381   /* check point is valid */
382   if (pid < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be >= 0");
383   if (pid >= gfield->L) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be < %D",gfield->L);
384   if (gfield->active == PETSC_FALSE) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Field \"%s\" is not active. You must call DataFieldGetAccess() before point data can be retrivied",gfield->name);
385 #endif
386   *ctx_p = __DATATFIELD_point_access_offset(gfield->data,pid,gfield->atomic_size,offset);
387   PetscFunctionReturn(0);
388 }
389 
390 PetscErrorCode DataFieldRestoreAccess(DataField gfield)
391 {
392   PetscFunctionBegin;
393   if (gfield->active == PETSC_FALSE) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Field \"%s\" is not active. You must call DataFieldGetAccess()", gfield->name);
394   gfield->active = PETSC_FALSE;
395   PetscFunctionReturn(0);
396 }
397 
398 PetscErrorCode DataFieldVerifyAccess(const DataField gfield,const size_t size)
399 {
400   PetscFunctionBegin;
401 #ifdef DATAFIELD_POINT_ACCESS_GUARD
402   if (gfield->atomic_size != size) SETERRQ3(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 );
403 #endif
404   PetscFunctionReturn(0);
405 }
406 
407 PetscErrorCode DataFieldGetAtomicSize(const DataField gfield,size_t *size)
408 {
409   PetscFunctionBegin;
410   if (size) {*size = gfield->atomic_size;}
411   PetscFunctionReturn(0);
412 }
413 
414 PetscErrorCode DataFieldGetEntries(const DataField gfield,void **data)
415 {
416   PetscFunctionBegin;
417   if (data) {*data = gfield->data;}
418   PetscFunctionReturn(0);
419 }
420 
421 PetscErrorCode DataFieldRestoreEntries(const DataField gfield,void **data)
422 {
423   PetscFunctionBegin;
424   if (data) {*data = NULL;}
425   PetscFunctionReturn(0);
426 }
427 
428 /* y = x */
429 PetscErrorCode DataBucketCopyPoint(const DataBucket xb,const PetscInt pid_x,
430                          const DataBucket yb,const PetscInt pid_y)
431 {
432   PetscInt f;
433   PetscErrorCode ierr;
434 
435   PetscFunctionBegin;
436   for (f = 0; f < xb->nfields; ++f) {
437     void *dest;
438     void *src;
439 
440     ierr = DataFieldGetAccess(xb->field[f]);CHKERRQ(ierr);
441     if (xb != yb) { ierr = DataFieldGetAccess( yb->field[f]);CHKERRQ(ierr); }
442     ierr = DataFieldAccessPoint(xb->field[f],pid_x, &src);CHKERRQ(ierr);
443     ierr = DataFieldAccessPoint(yb->field[f],pid_y, &dest);CHKERRQ(ierr);
444     ierr = PetscMemcpy(dest, src, xb->field[f]->atomic_size);CHKERRQ(ierr);
445     ierr = DataFieldRestoreAccess(xb->field[f]);CHKERRQ(ierr);
446     if (xb != yb) {ierr = DataFieldRestoreAccess(yb->field[f]);CHKERRQ(ierr);}
447   }
448   PetscFunctionReturn(0);
449 }
450 
451 PetscErrorCode DataBucketCreateFromSubset(DataBucket DBIn,const PetscInt N,const PetscInt list[],DataBucket *DB)
452 {
453   PetscInt nfields;
454   DataField *fields;
455   PetscInt f,L,buffer,allocated,p;
456   PetscErrorCode ierr;
457 
458   PetscFunctionBegin;
459   ierr = DataBucketCreate(DB);CHKERRQ(ierr);
460   /* copy contents of DBIn */
461   ierr = DataBucketGetDataFields(DBIn,&nfields,&fields);CHKERRQ(ierr);
462   ierr = DataBucketGetSizes(DBIn,&L,&buffer,&allocated);CHKERRQ(ierr);
463   for (f = 0; f < nfields; ++f) {
464     ierr = DataBucketRegisterField(*DB,"DataBucketCreateFromSubset",fields[f]->name,fields[f]->atomic_size,NULL);CHKERRQ(ierr);
465   }
466   ierr = DataBucketFinalize(*DB);CHKERRQ(ierr);
467   ierr = DataBucketSetSizes(*DB,L,buffer);CHKERRQ(ierr);
468   /* now copy the desired guys from DBIn => DB */
469   for (p = 0; p < N; ++p) {
470     ierr = DataBucketCopyPoint(DBIn,list[p], *DB,p);CHKERRQ(ierr);
471   }
472   PetscFunctionReturn(0);
473 }
474 
475 /* insert into an exisitng location */
476 PetscErrorCode DataFieldInsertPoint(const DataField field,const PetscInt index,const void *ctx)
477 {
478   PetscErrorCode ierr;
479 
480   PetscFunctionBegin;
481 #ifdef DATAFIELD_POINT_ACCESS_GUARD
482   /* check point is valid */
483   if (index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be >= 0");
484   if (index >= field->L) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be < %D",field->L);
485 #endif
486   ierr = PetscMemcpy(__DATATFIELD_point_access(field->data,index,field->atomic_size), ctx, field->atomic_size);CHKERRQ(ierr);
487   PetscFunctionReturn(0);
488 }
489 
490 /* remove data at index - replace with last point */
491 PetscErrorCode DataBucketRemovePointAtIndex(const DataBucket db,const PetscInt index)
492 {
493   PetscInt       f;
494   PetscBool      any_active_fields;
495   PetscErrorCode ierr;
496 
497   PetscFunctionBegin;
498 #ifdef DATAFIELD_POINT_ACCESS_GUARD
499   /* check point is valid */
500   if (index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be >= 0");
501   if (index >= db->allocated) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be < %D",db->L+db->buffer);
502 #endif
503   ierr = DataBucketQueryForActiveFields(db,&any_active_fields);CHKERRQ(ierr);
504   if (any_active_fields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot safely remove point as at least one DataField is currently being accessed");
505   if (index >= db->L) { /* this point is not in the list - no need to error, but I will anyway */
506     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"You should not be trying to remove point at index=%D since it's < db->L = %D", index, db->L);
507   }
508   if (index != db->L-1) { /* not last point in list */
509     for (f = 0; f < db->nfields; ++f) {
510       DataField field = db->field[f];
511 
512       /* copy then remove */
513       ierr = DataFieldCopyPoint(db->L-1, field, index, field);CHKERRQ(ierr);
514       /* DataFieldZeroPoint(field,index); */
515     }
516   }
517   /* decrement size */
518   /* this will zero out an crap at the end of the list */
519   ierr = DataBucketRemovePoint(db);CHKERRQ(ierr);
520   PetscFunctionReturn(0);
521 }
522 
523 /* copy x into y */
524 PetscErrorCode DataFieldCopyPoint(const PetscInt pid_x,const DataField field_x,
525                         const PetscInt pid_y,const DataField field_y )
526 {
527   PetscErrorCode ierr;
528 
529   PetscFunctionBegin;
530 #ifdef DATAFIELD_POINT_ACCESS_GUARD
531   /* check point is valid */
532   if (pid_x < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"(IN) index must be >= 0");
533   if (pid_x >= field_x->L) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"(IN) index must be < %D",field_x->L);
534   if (pid_y < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"(OUT) index must be >= 0");
535   if (pid_y >= field_y->L) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"(OUT) index must be < %D",field_y->L);
536   if( field_y->atomic_size != field_x->atomic_size ) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"atomic size must match");
537 #endif
538   ierr = PetscMemcpy(__DATATFIELD_point_access(field_y->data,pid_y,field_y->atomic_size),
539                      __DATATFIELD_point_access(field_x->data,pid_x,field_x->atomic_size),
540                      field_y->atomic_size);CHKERRQ(ierr);
541   PetscFunctionReturn(0);
542 }
543 
544 
545 /* zero only the datafield at this point */
546 PetscErrorCode DataFieldZeroPoint(const DataField field,const PetscInt index)
547 {
548   PetscErrorCode ierr;
549 
550   PetscFunctionBegin;
551 #ifdef DATAFIELD_POINT_ACCESS_GUARD
552   /* check point is valid */
553   if (index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be >= 0");
554   if (index >= field->L) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be < %D",field->L);
555 #endif
556   ierr = PetscMemzero(__DATATFIELD_point_access(field->data,index,field->atomic_size), field->atomic_size);CHKERRQ(ierr);
557   PetscFunctionReturn(0);
558 }
559 
560 /* zero ALL data for this point */
561 PetscErrorCode DataBucketZeroPoint(const DataBucket db,const PetscInt index)
562 {
563   PetscInt f;
564   PetscErrorCode ierr;
565 
566   PetscFunctionBegin;
567   /* check point is valid */
568   if (index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be >= 0");
569   if (index >= db->allocated) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"index must be < %D",db->allocated);
570   for (f = 0; f < db->nfields; ++f) {
571     DataField field = db->field[f];
572     ierr = DataFieldZeroPoint(field,index);CHKERRQ(ierr);
573   }
574   PetscFunctionReturn(0);
575 }
576 
577 /* increment */
578 PetscErrorCode DataBucketAddPoint(DataBucket db)
579 {
580   PetscErrorCode ierr;
581 
582   PetscFunctionBegin;
583   ierr = DataBucketSetSizes(db,db->L+1,-1);CHKERRQ(ierr);
584   PetscFunctionReturn(0);
585 }
586 
587 /* decrement */
588 PetscErrorCode DataBucketRemovePoint(DataBucket db)
589 {
590   PetscErrorCode ierr;
591 
592   PetscFunctionBegin;
593   ierr = DataBucketSetSizes(db,db->L-1,-1);CHKERRQ(ierr);
594   PetscFunctionReturn(0);
595 }
596 
597 PetscErrorCode _DataFieldViewBinary(DataField field,FILE *fp)
598 {
599   PetscErrorCode ierr;
600 
601   PetscFunctionBegin;
602   ierr = PetscFPrintf(PETSC_COMM_SELF, fp,"<DataField>\n");CHKERRQ(ierr);
603   ierr = PetscFPrintf(PETSC_COMM_SELF, fp,"%D\n", field->L);CHKERRQ(ierr);
604   ierr = PetscFPrintf(PETSC_COMM_SELF, fp,"%zu\n",field->atomic_size);CHKERRQ(ierr);
605   ierr = PetscFPrintf(PETSC_COMM_SELF, fp,"%s\n", field->registeration_function);CHKERRQ(ierr);
606   ierr = PetscFPrintf(PETSC_COMM_SELF, fp,"%s\n", field->name);CHKERRQ(ierr);
607   fwrite(field->data, field->atomic_size, field->L, fp);
608   ierr = PetscFPrintf(PETSC_COMM_SELF, fp,"\n</DataField>\n");CHKERRQ(ierr);
609   PetscFunctionReturn(0);
610 }
611 
612 PetscErrorCode _DataBucketRegisterFieldFromFile(FILE *fp,DataBucket db)
613 {
614   PetscBool      val;
615   DataField      gfield;
616   char           dummy[100];
617   char           registeration_function[5000];
618   char           field_name[5000];
619   PetscInt       L;
620   size_t         atomic_size,strL;
621   PetscErrorCode ierr;
622 
623   PetscFunctionBegin;
624   /* check we haven't finalised the registration of fields */
625   /*
626    if(db->finalised==PETSC_TRUE) {
627    printf("ERROR: DataBucketFinalize() has been called. Cannot register more fields\n");
628    ERROR();
629    }
630    */
631   /* read file contents */
632   if (!fgets(dummy,99,fp))  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
633   if (fscanf(fp, "%" PetscInt_FMT "\n",&L) != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
634   if (fscanf(fp, "%zu\n",&atomic_size) != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
635   if (!fgets(registeration_function,4999,fp))  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
636   strL = strlen(registeration_function);
637   if (strL > 1) {
638     registeration_function[strL-1] = 0;
639   }
640   if (!fgets(field_name,4999,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
641   strL = strlen(field_name);
642   if (strL > 1) {
643     field_name[strL-1] = 0;
644   }
645 
646 #ifdef DATA_BUCKET_LOG
647   ierr = PetscPrintf(PETSC_COMM_SELF,"  ** read L=%D; atomic_size=%zu; reg_func=\"%s\"; name=\"%s\" \n", L,atomic_size,registeration_function,field_name);CHKERRQ(ierr);
648 #endif
649   /* check for repeated name */
650   ierr = StringInList( field_name, db->nfields, (const DataField*)db->field, &val );CHKERRQ(ierr);
651   if (val == PETSC_TRUE) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot add same field twice");
652   /* create new space for data */
653   ierr = PetscRealloc(sizeof(DataField)*(db->nfields+1), &db->field);CHKERRQ(ierr);
654   /* add field */
655   ierr = DataFieldCreate( registeration_function, field_name, atomic_size, L, &gfield );CHKERRQ(ierr);
656   /* copy contents of file */
657   if (fread(gfield->data, gfield->atomic_size, gfield->L, fp) != (size_t) gfield->L) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
658 #ifdef DATA_BUCKET_LOG
659   ierr = PetscPrintf(PETSC_COMM_SELF,"  ** read %zu bytes for DataField \"%s\" \n", gfield->atomic_size * gfield->L, field_name);CHKERRQ(ierr);
660 #endif
661   /* finish reading meta data */
662   if (!fgets(dummy,99,fp))  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
663   if (!fgets(dummy,99,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
664   db->field[db->nfields] = gfield;
665   db->nfields++;
666   PetscFunctionReturn(0);
667 }
668 
669 PetscErrorCode _DataBucketViewAscii_HeaderWrite_v00(FILE *fp)
670 {
671   PetscErrorCode ierr;
672 
673   PetscFunctionBegin;
674   ierr = PetscFPrintf(PETSC_COMM_SELF,fp,"<DataBucketHeader>\n");CHKERRQ(ierr);
675   ierr = PetscFPrintf(PETSC_COMM_SELF,fp,"type=DataBucket\n");CHKERRQ(ierr);
676   ierr = PetscFPrintf(PETSC_COMM_SELF,fp,"format=ascii\n");CHKERRQ(ierr);
677   ierr = PetscFPrintf(PETSC_COMM_SELF,fp,"version=0.0\n");CHKERRQ(ierr);
678   ierr = PetscFPrintf(PETSC_COMM_SELF,fp,"options=\n");CHKERRQ(ierr);
679   ierr = PetscFPrintf(PETSC_COMM_SELF,fp,"</DataBucketHeader>\n");CHKERRQ(ierr);
680   PetscFunctionReturn(0);
681 }
682 
683 PetscErrorCode _DataBucketViewAscii_HeaderRead_v00(FILE *fp)
684 {
685   char           dummy[100];
686   size_t         strL;
687   PetscBool      flg;
688   PetscErrorCode ierr;
689 
690   PetscFunctionBegin;
691   /* header open */
692   if (!fgets(dummy,99,fp))  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
693 
694   /* type */
695   if (!fgets(dummy,99,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
696   strL = strlen(dummy);
697   if (strL > 1) {dummy[strL-1] = 0;}
698   ierr = PetscStrcmp(dummy, "type=DataBucket", &flg);CHKERRQ(ierr);
699   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Data file doesn't contain a DataBucket type");
700   /* format */
701   if (!fgets(dummy,99,fp))  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
702   /* version */
703   if (!fgets(dummy,99,fp))  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
704   strL = strlen(dummy);
705   if (strL > 1) { dummy[strL-1] = 0; }
706   ierr = PetscStrcmp(dummy, "version=0.0", &flg);CHKERRQ(ierr);
707   if (!flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"DataBucket file must be parsed with version=0.0 : You tried %s", dummy);
708   /* options */
709   if (!fgets(dummy,99,fp))  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
710   /* header close */
711   if (!fgets(dummy,99,fp))  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
712   PetscFunctionReturn(0);
713 }
714 
715 PetscErrorCode _DataBucketLoadFromFileBinary_SEQ(const char filename[],DataBucket *_db)
716 {
717   DataBucket db;
718   FILE *fp;
719   PetscInt L,buffer,f,nfields;
720   PetscErrorCode ierr;
721 
722   PetscFunctionBegin;
723 #ifdef DATA_BUCKET_LOG
724   ierr = PetscPrintf(PETSC_COMM_SELF,"** DataBucketLoadFromFile **\n");CHKERRQ(ierr);
725 #endif
726   /* open file */
727   fp = fopen(filename,"rb");
728   if (fp == NULL) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file with name %s", filename);
729   /* read header */
730   ierr = _DataBucketViewAscii_HeaderRead_v00(fp);CHKERRQ(ierr);
731   if (fscanf(fp,"%" PetscInt_FMT "\n%" PetscInt_FMT "\n%" PetscInt_FMT "\n",&L,&buffer,&nfields) != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Incorrect file format");
732   ierr = DataBucketCreate(&db);CHKERRQ(ierr);
733   for (f = 0; f < nfields; ++f) {
734     ierr = _DataBucketRegisterFieldFromFile(fp,db);CHKERRQ(ierr);
735   }
736   fclose(fp);
737   ierr = DataBucketFinalize(db);CHKERRQ(ierr);
738   /*
739    DataBucketSetSizes(db,L,buffer);
740    */
741   db->L = L;
742   db->buffer = buffer;
743   db->allocated = L + buffer;
744   *_db = db;
745   PetscFunctionReturn(0);
746 }
747 
748 PetscErrorCode DataBucketLoadFromFile(MPI_Comm comm,const char filename[],DataBucketViewType type,DataBucket *db)
749 {
750   PetscMPIInt    nproc,rank;
751   PetscErrorCode ierr;
752 
753   PetscFunctionBegin;
754   ierr = MPI_Comm_size(comm,&nproc);CHKERRQ(ierr);
755   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
756 #ifdef DATA_BUCKET_LOG
757   ierr = PetscPrintf(PETSC_COMM_SELF,"** DataBucketLoadFromFile **\n");CHKERRQ(ierr);
758 #endif
759   if (type == DATABUCKET_VIEW_STDOUT) {
760   } else if (type == DATABUCKET_VIEW_ASCII) {
761     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot be implemented as we don't know the underlying particle data structure");
762   } else if (type == DATABUCKET_VIEW_BINARY) {
763     if (nproc == 1) {
764       ierr = _DataBucketLoadFromFileBinary_SEQ(filename,db);CHKERRQ(ierr);
765     } else {
766       char name[PETSC_MAX_PATH_LEN];
767 
768       ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN-1, "%s_p%1.5d", filename, rank);CHKERRQ(ierr);
769       ierr = _DataBucketLoadFromFileBinary_SEQ(name, db);CHKERRQ(ierr);
770     }
771   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer requested");
772   PetscFunctionReturn(0);
773 }
774 
775 PetscErrorCode _DataBucketViewBinary(DataBucket db,const char filename[])
776 {
777   FILE          *fp = NULL;
778   PetscInt       f;
779   PetscErrorCode ierr;
780 
781   PetscFunctionBegin;
782   fp = fopen(filename,"wb");
783   if (fp == NULL) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot open file with name %s", filename);
784   /* db header */
785   ierr =_DataBucketViewAscii_HeaderWrite_v00(fp);CHKERRQ(ierr);
786   /* meta-data */
787   ierr = PetscFPrintf(PETSC_COMM_SELF, fp, "%D\n%D\n%D\n", db->L,db->buffer,db->nfields);CHKERRQ(ierr);
788   /* load datafields */
789   for (f = 0; f < db->nfields; ++f) {
790     ierr = _DataFieldViewBinary(db->field[f],fp);CHKERRQ(ierr);
791   }
792   fclose(fp);
793   PetscFunctionReturn(0);
794 }
795 
796 PetscErrorCode DataBucketView_SEQ(DataBucket db,const char filename[],DataBucketViewType type)
797 {
798   PetscErrorCode ierr;
799 
800   PetscFunctionBegin;
801   switch (type) {
802   case DATABUCKET_VIEW_STDOUT:
803   {
804     PetscInt f;
805     double memory_usage_total = 0.0;
806 
807     ierr = PetscPrintf(PETSC_COMM_SELF,"DataBucketView(SEQ): (\"%s\")\n",filename);CHKERRQ(ierr);
808     ierr = PetscPrintf(PETSC_COMM_SELF,"  L                  = %D \n", db->L);CHKERRQ(ierr);
809     ierr = PetscPrintf(PETSC_COMM_SELF,"  buffer             = %D \n", db->buffer);CHKERRQ(ierr);
810     ierr = PetscPrintf(PETSC_COMM_SELF,"  allocated          = %D \n", db->allocated);CHKERRQ(ierr);
811     ierr = PetscPrintf(PETSC_COMM_SELF,"  nfields registered = %D \n", db->nfields);CHKERRQ(ierr);
812     for (f = 0; f < db->nfields; ++f) {
813       double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
814       ierr = PetscPrintf(PETSC_COMM_SELF,"    [%3D]: field name  ==>> %30s : Mem. usage = %1.2e (MB) \n", f, db->field[f]->name, memory_usage_f );CHKERRQ(ierr);
815       ierr = PetscPrintf(PETSC_COMM_SELF,"           blocksize          = %D \n", db->field[f]->bs);CHKERRQ(ierr);
816       if (db->field[f]->bs != 1) {
817         ierr = PetscPrintf(PETSC_COMM_SELF,"           atomic size        = %zu [full block, bs=%D]\n", db->field[f]->atomic_size,db->field[f]->bs);CHKERRQ(ierr);
818         ierr = PetscPrintf(PETSC_COMM_SELF,"           atomic size/item   = %zu \n", db->field[f]->atomic_size/db->field[f]->bs);CHKERRQ(ierr);
819       } else {
820         ierr = PetscPrintf(PETSC_COMM_SELF,"           atomic size        = %zu \n", db->field[f]->atomic_size);CHKERRQ(ierr);
821       }
822       memory_usage_total += memory_usage_f;
823     }
824     ierr = PetscPrintf(PETSC_COMM_SELF,"  Total mem. usage                                                      = %1.2e (MB) \n", memory_usage_total);CHKERRQ(ierr);
825   }
826   break;
827   case DATABUCKET_VIEW_ASCII:
828   {
829     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot be implemented as we don't know the underlying particle data structure");
830   }
831   break;
832   case DATABUCKET_VIEW_BINARY:
833   {
834     ierr = _DataBucketViewBinary(db,filename);CHKERRQ(ierr);
835   }
836   break;
837   case DATABUCKET_VIEW_HDF5:
838   {
839     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"No HDF5 support");
840   }
841   break;
842   default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unknown viewer method requested");
843   }
844   PetscFunctionReturn(0);
845 }
846 
847 PetscErrorCode DataBucketView_MPI(MPI_Comm comm,DataBucket db,const char filename[],DataBucketViewType type)
848 {
849   PetscErrorCode ierr;
850 
851   PetscFunctionBegin;
852   switch (type) {
853   case DATABUCKET_VIEW_STDOUT:
854   {
855     PetscInt f;
856     PetscInt L,buffer,allocated;
857     double memory_usage_total,memory_usage_total_local = 0.0;
858     PetscMPIInt rank;
859 
860     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
861     ierr = DataBucketGetGlobalSizes(comm,db,&L,&buffer,&allocated);CHKERRQ(ierr);
862     for (f = 0; f < db->nfields; ++f) {
863       double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
864       memory_usage_total_local += memory_usage_f;
865     }
866     ierr = MPI_Allreduce(&memory_usage_total_local,&memory_usage_total,1,MPI_DOUBLE,MPI_SUM,comm);CHKERRQ(ierr);
867     ierr = PetscPrintf(comm,"DataBucketView(MPI): (\"%s\")\n",filename);CHKERRQ(ierr);
868     ierr = PetscPrintf(comm,"  L                  = %D \n", L);CHKERRQ(ierr);
869     ierr = PetscPrintf(comm,"  buffer (max)       = %D \n", buffer);CHKERRQ(ierr);
870     ierr = PetscPrintf(comm,"  allocated          = %D \n", allocated);CHKERRQ(ierr);
871     ierr = PetscPrintf(comm,"  nfields registered = %D \n", db->nfields);CHKERRQ(ierr);
872     for (f=0; f<db->nfields; f++) {
873       double memory_usage_f = (double)(db->field[f]->atomic_size * db->allocated) * 1.0e-6;
874       ierr = PetscPrintf(PETSC_COMM_SELF,"    [%3D]: field name  ==>> %30s : Mem. usage = %1.2e (MB) : rank0\n", f, db->field[f]->name, memory_usage_f);CHKERRQ(ierr);
875     }
876     ierr = PetscPrintf(PETSC_COMM_SELF,"  Total mem. usage                                                      = %1.2e (MB) : collective\n", memory_usage_total);CHKERRQ(ierr);
877   }
878   break;
879   case DATABUCKET_VIEW_ASCII:
880   {
881     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot be implemented as we don't know the underlying data structure");
882   }
883   break;
884   case DATABUCKET_VIEW_BINARY:
885   {
886     char        name[PETSC_MAX_PATH_LEN];
887     PetscMPIInt rank;
888 
889     /* create correct extension */
890     ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
891     ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN-1, "%s_p%1.5d", filename, rank);CHKERRQ(ierr);
892     ierr = _DataBucketViewBinary(db, name);CHKERRQ(ierr);
893   }
894   break;
895   case DATABUCKET_VIEW_HDF5:
896   {
897     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for HDF5");
898   }
899   break;
900   default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unknown viewer method requested");
901   }
902   PetscFunctionReturn(0);
903 }
904 
905 PetscErrorCode DataBucketView(MPI_Comm comm,DataBucket db,const char filename[],DataBucketViewType type)
906 {
907   PetscMPIInt nproc;
908   PetscErrorCode ierr;
909 
910   PetscFunctionBegin;
911   ierr = MPI_Comm_size(comm,&nproc);CHKERRQ(ierr);
912   if (nproc == 1) {
913     ierr = DataBucketView_SEQ(db,filename,type);CHKERRQ(ierr);
914   } else {
915     ierr = DataBucketView_MPI(comm,db,filename,type);CHKERRQ(ierr);
916   }
917   PetscFunctionReturn(0);
918 }
919 
920 PetscErrorCode DataBucketDuplicateFields(DataBucket dbA,DataBucket *dbB)
921 {
922   DataBucket db2;
923   PetscInt f;
924   PetscErrorCode ierr;
925 
926   PetscFunctionBegin;
927   ierr = DataBucketCreate(&db2);CHKERRQ(ierr);
928   /* copy contents from dbA into db2 */
929   for (f = 0; f < dbA->nfields; ++f) {
930     DataField field;
931     size_t    atomic_size;
932     char      *name;
933 
934     field = dbA->field[f];
935     atomic_size = field->atomic_size;
936     name        = field->name;
937     ierr = DataBucketRegisterField(db2,"DataBucketDuplicateFields",name,atomic_size,NULL);CHKERRQ(ierr);
938   }
939   ierr = DataBucketFinalize(db2);CHKERRQ(ierr);
940   ierr = DataBucketSetInitialSizes(db2,0,1000);CHKERRQ(ierr);
941   *dbB = db2;
942   PetscFunctionReturn(0);
943 }
944 
945 /*
946  Insert points from db2 into db1
947  db1 <<== db2
948  */
949 PetscErrorCode DataBucketInsertValues(DataBucket db1,DataBucket db2)
950 {
951   PetscInt n_mp_points1,n_mp_points2;
952   PetscInt n_mp_points1_new,p;
953   PetscErrorCode ierr;
954 
955   PetscFunctionBegin;
956   ierr = DataBucketGetSizes(db1,&n_mp_points1,0,0);CHKERRQ(ierr);
957   ierr = DataBucketGetSizes(db2,&n_mp_points2,0,0);CHKERRQ(ierr);
958   n_mp_points1_new = n_mp_points1 + n_mp_points2;
959   ierr = DataBucketSetSizes(db1,n_mp_points1_new,-1);CHKERRQ(ierr);
960   for (p = 0; p < n_mp_points2; ++p) {
961     /* db1 <<== db2 */
962     ierr = DataBucketCopyPoint(db2,p, db1,(n_mp_points1 + p));CHKERRQ(ierr);
963   }
964   PetscFunctionReturn(0);
965 }
966 
967 /* helpers for parallel send/recv */
968 PetscErrorCode DataBucketCreatePackedArray(DataBucket db,size_t *bytes,void **buf)
969 {
970   PetscInt       f;
971   size_t         sizeof_marker_contents;
972   void          *buffer;
973   PetscErrorCode ierr;
974 
975   PetscFunctionBegin;
976   sizeof_marker_contents = 0;
977   for (f = 0; f < db->nfields; ++f) {
978     DataField df = db->field[f];
979     sizeof_marker_contents += df->atomic_size;
980   }
981   ierr = PetscMalloc(sizeof_marker_contents, &buffer);CHKERRQ(ierr);
982   ierr = PetscMemzero(buffer, sizeof_marker_contents);CHKERRQ(ierr);
983   if (bytes) {*bytes = sizeof_marker_contents;}
984   if (buf)   {*buf   = buffer;}
985   PetscFunctionReturn(0);
986 }
987 
988 PetscErrorCode DataBucketDestroyPackedArray(DataBucket db,void **buf)
989 {
990   PetscErrorCode ierr;
991 
992   PetscFunctionBegin;
993   if (buf) {
994     ierr = PetscFree(*buf);CHKERRQ(ierr);
995     *buf = NULL;
996   }
997   PetscFunctionReturn(0);
998 }
999 
1000 PetscErrorCode DataBucketFillPackedArray(DataBucket db,const PetscInt index,void *buf)
1001 {
1002   PetscInt       f;
1003   void          *data, *data_p;
1004   size_t         asize, offset;
1005   PetscErrorCode ierr;
1006 
1007   PetscFunctionBegin;
1008   offset = 0;
1009   for (f = 0; f < db->nfields; ++f) {
1010     DataField df = db->field[f];
1011 
1012     asize = df->atomic_size;
1013     data = (void*)( df->data );
1014     data_p = (void*)( (char*)data + index*asize );
1015     ierr = PetscMemcpy((void*)((char*)buf + offset), data_p, asize);CHKERRQ(ierr);
1016     offset = offset + asize;
1017   }
1018   PetscFunctionReturn(0);
1019 }
1020 
1021 PetscErrorCode DataBucketInsertPackedArray(DataBucket db,const PetscInt idx,void *data)
1022 {
1023   PetscInt f;
1024   void *data_p;
1025   size_t offset;
1026   PetscErrorCode ierr;
1027 
1028   PetscFunctionBegin;
1029   offset = 0;
1030   for (f = 0; f < db->nfields; ++f) {
1031     DataField df = db->field[f];
1032 
1033     data_p = (void*)( (char*)data + offset );
1034     ierr = DataFieldInsertPoint(df, idx, (void*)data_p);CHKERRQ(ierr);
1035     offset = offset + df->atomic_size;
1036   }
1037   PetscFunctionReturn(0);
1038 }
1039