Actual source code: data_ex.c

petsc-3.11.4 2019-09-28
Report Typos and Errors
  1: /*
  2: Build a few basic tools to help with partitioned domains.

  4: 1)
  5: On each processor, have a DomainExchangerTopology.
  6: This is a doubly-connected edge list which enumerates the 
  7: communication paths between connected processors. By numbering
  8: these paths we can always uniquely assign message identifers.

 10:         edge
 11:          10
 12: proc  --------->  proc
 13:  0    <--------    1
 14:          11
 15:         twin

 17: Eg: Proc 0 send to proc 1 with message id is 10. To recieve the correct
 18: message, proc 1 looks for the edge connected to proc 0, and then the
 19: messgae id comes from the twin of that edge

 21: 2)
 22: A DomainExchangerArrayPacker.
 23: A little function which given a piece of data, will memcpy the data into
 24: an array (which will be sent to procs) into the correct place.

 26: On Proc 1 we sent data to procs 0,2,3. The data is on different lengths.
 27: All data gets jammed into single array. Need to "jam" data into correct locations
 28: The Packer knows how much is to going to each processor and keeps track of the inserts
 29: so as to avoid ever packing TOO much into one slot, and inevatbly corrupting some memory

 31: data to 0    data to 2       data to 3

 33: |--------|-----------------|--|


 36: User has to unpack message themselves. I can get you the pointer for each i 
 37: entry, but you'll have to cast it to the appropriate data type.




 42: Phase A: Build topology

 44: Phase B: Define message lengths

 46: Phase C: Pack data

 48: Phase D: Send data

 50: + Constructor
 51: DMSwarmDataExCreate()
 52: + Phase A
 53: DMSwarmDataExTopologyInitialize()
 54: DMSwarmDataExTopologyAddNeighbour()
 55: DMSwarmDataExTopologyAddNeighbour()
 56: DMSwarmDataExTopologyFinalize()
 57: + Phase B
 58: DMSwarmDataExZeroAllSendCount()
 59: DMSwarmDataExAddToSendCount()
 60: DMSwarmDataExAddToSendCount()
 61: DMSwarmDataExAddToSendCount()
 62: + Phase C
 63: DMSwarmDataExPackInitialize()
 64: DMSwarmDataExPackData()
 65: DMSwarmDataExPackData()
 66: DMSwarmDataExPackFinalize()
 67: +Phase D
 68: DMSwarmDataExBegin()
 69:  ... perform any calculations ...
 70: DMSwarmDataExEnd()

 72: ... user calls any getters here ...


 75: */
 76:  #include <petscvec.h>
 77:  #include <petscmat.h>

 79: #include "../src/dm/impls/swarm/data_ex.h"

 81: const char *status_names[] = {"initialized", "finalized", "unknown"};

 83: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerTopologySetup;
 84: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerBegin;
 85: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerEnd;
 86: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerSendCount;
 87: PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerPack;

 89: PetscErrorCode DMSwarmDataExCreate(MPI_Comm comm,const PetscInt count, DMSwarmDataEx *ex)
 90: {
 92:   DMSwarmDataEx         d;

 95:   PetscMalloc(sizeof(struct _p_DMSwarmDataEx), &d);
 96:   PetscMemzero(d, sizeof(struct _p_DMSwarmDataEx));
 97:   MPI_Comm_dup(comm,&d->comm);
 98:   MPI_Comm_rank(d->comm,&d->rank);

100:   d->instance = count;

102:   d->topology_status        = DEOBJECT_STATE_UNKNOWN;
103:   d->message_lengths_status = DEOBJECT_STATE_UNKNOWN;
104:   d->packer_status          = DEOBJECT_STATE_UNKNOWN;
105:   d->communication_status   = DEOBJECT_STATE_UNKNOWN;

107:   d->n_neighbour_procs = -1;
108:   d->neighbour_procs   = NULL;

110:   d->messages_to_be_sent      = NULL;
111:   d->message_offsets          = NULL;
112:   d->messages_to_be_recvieved = NULL;

114:   d->unit_message_size   = -1;
115:   d->send_message        = NULL;
116:   d->send_message_length = -1;
117:   d->recv_message        = NULL;
118:   d->recv_message_length = -1;
119:   d->total_pack_cnt      = -1;
120:   d->pack_cnt            = NULL;

122:   d->send_tags = NULL;
123:   d->recv_tags = NULL;

125:   d->_stats    = NULL;
126:   d->_requests = NULL;
127:   *ex = d;
128:   return(0);
129: }

131: /*
132:     This code is horrible, who let it get into master.

134:     Should be printing to a viewer, should not be using PETSC_COMM_WORLD

136: */
137: PetscErrorCode DMSwarmDataExView(DMSwarmDataEx d)
138: {
139:   PetscMPIInt    p;

143:   PetscPrintf( PETSC_COMM_WORLD, "DMSwarmDataEx: instance=%D\n",d->instance);
144:   PetscPrintf( PETSC_COMM_WORLD, "  topology status:        %s \n", status_names[d->topology_status]);
145:   PetscPrintf( PETSC_COMM_WORLD, "  message lengths status: %s \n", status_names[d->message_lengths_status] );
146:   PetscPrintf( PETSC_COMM_WORLD, "  packer status status:   %s \n", status_names[d->packer_status] );
147:   PetscPrintf( PETSC_COMM_WORLD, "  communication status:   %s \n", status_names[d->communication_status] );

149:   if (d->topology_status == DEOBJECT_FINALIZED) {
150:     PetscPrintf( PETSC_COMM_WORLD, "  Topology:\n");
151:     PetscSynchronizedPrintf( PETSC_COMM_WORLD, "    [%d] neighbours: %d \n", d->rank, d->n_neighbour_procs );
152:     for (p=0; p<d->n_neighbour_procs; p++) {
153:       PetscSynchronizedPrintf( PETSC_COMM_WORLD, "    [%d]   neighbour[%d] = %d \n", d->rank, p, d->neighbour_procs[p]);
154:     }
155:     PetscSynchronizedFlush(PETSC_COMM_WORLD,stdout);
156:   }

158:   if (d->message_lengths_status == DEOBJECT_FINALIZED) {
159:     PetscPrintf( PETSC_COMM_WORLD, "  Message lengths:\n");
160:     PetscSynchronizedPrintf( PETSC_COMM_WORLD, "    [%d] atomic size: %ld \n", d->rank, (long int)d->unit_message_size );
161:     for (p=0; p<d->n_neighbour_procs; p++) {
162:       PetscSynchronizedPrintf( PETSC_COMM_WORLD, "    [%d] >>>>> ( %D units :: tag = %d ) >>>>> [%d] \n", d->rank, d->messages_to_be_sent[p], d->send_tags[p], d->neighbour_procs[p] );
163:     }
164:     for (p=0; p<d->n_neighbour_procs; p++) {
165:       PetscSynchronizedPrintf( PETSC_COMM_WORLD, "    [%d] <<<<< ( %D units :: tag = %d ) <<<<< [%d] \n", d->rank, d->messages_to_be_recvieved[p], d->recv_tags[p], d->neighbour_procs[p] );
166:     }
167:     PetscSynchronizedFlush(PETSC_COMM_WORLD,stdout);
168:   }
169:   if (d->packer_status == DEOBJECT_FINALIZED) {}
170:   if (d->communication_status == DEOBJECT_FINALIZED) {}
171:   return(0);
172: }

174: PetscErrorCode DMSwarmDataExDestroy(DMSwarmDataEx d)
175: {

179:   MPI_Comm_free(&d->comm);
180:   if (d->neighbour_procs) {PetscFree(d->neighbour_procs);}
181:   if (d->messages_to_be_sent) {PetscFree(d->messages_to_be_sent);}
182:   if (d->message_offsets) {PetscFree(d->message_offsets);}
183:   if (d->messages_to_be_recvieved) {PetscFree(d->messages_to_be_recvieved);}
184:   if (d->send_message) {PetscFree(d->send_message);}
185:   if (d->recv_message) {PetscFree(d->recv_message);}
186:   if (d->pack_cnt) {PetscFree(d->pack_cnt);}
187:   if (d->send_tags) {PetscFree(d->send_tags);}
188:   if (d->recv_tags) {PetscFree(d->recv_tags);}
189:   if (d->_stats) {PetscFree(d->_stats);}
190:   if (d->_requests) {PetscFree(d->_requests);}
191:   PetscFree(d);
192:   return(0);
193: }

195: /* === Phase A === */

197: PetscErrorCode DMSwarmDataExTopologyInitialize(DMSwarmDataEx d)
198: {

202:   d->topology_status = DEOBJECT_INITIALIZED;
203:   d->n_neighbour_procs = 0;
204:   PetscFree(d->neighbour_procs);
205:   PetscFree(d->messages_to_be_sent);
206:   PetscFree(d->message_offsets);
207:   PetscFree(d->messages_to_be_recvieved);
208:   PetscFree(d->pack_cnt);
209:   PetscFree(d->send_tags);
210:   PetscFree(d->recv_tags);
211:   return(0);
212: }

214: PetscErrorCode DMSwarmDataExTopologyAddNeighbour(DMSwarmDataEx d,const PetscMPIInt proc_id)
215: {
216:   PetscMPIInt    n,found;
217:   PetscMPIInt    size;

221:   if (d->topology_status == DEOBJECT_FINALIZED) SETERRQ(d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology has been finalized. To modify or update call DMSwarmDataExTopologyInitialize() first");
222:   else if (d->topology_status != DEOBJECT_INITIALIZED) SETERRQ(d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be intialised. Call DMSwarmDataExTopologyInitialize() first");

224:   /* error on negative entries */
225:   if (proc_id < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Trying to set proc neighbour with a rank < 0");
226:   /* error on ranks larger than number of procs in communicator */
227:   MPI_Comm_size(d->comm,&size);
228:   if (proc_id >= size) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Trying to set proc neighbour %d with a rank >= size %d",proc_id,size);
229:   if (d->n_neighbour_procs == 0) {PetscMalloc1(1, &d->neighbour_procs);}
230:   /* check for proc_id */
231:   found = 0;
232:   for (n = 0; n < d->n_neighbour_procs; n++) {
233:     if (d->neighbour_procs[n] == proc_id) {
234:       found  = 1;
235:     }
236:   }
237:   if (found == 0) { /* add it to list */
238:     PetscRealloc(sizeof(PetscMPIInt)*(d->n_neighbour_procs+1), &d->neighbour_procs);
239:     d->neighbour_procs[ d->n_neighbour_procs ] = proc_id;
240:     d->n_neighbour_procs++;
241:   }
242:   return(0);
243: }

245: /*
246: counter: the index of the communication object
247: N: the number of processors
248: r0: rank of sender
249: r1: rank of receiver

251: procs = { 0, 1, 2, 3 }

253: 0 ==> 0                e=0
254: 0 ==> 1                e=1
255: 0 ==> 2                e=2
256: 0 ==> 3                e=3

258: 1 ==> 0                e=4
259: 1 ==> 1                e=5
260: 1 ==> 2                e=6
261: 1 ==> 3                e=7

263: 2 ==> 0                e=8
264: 2 ==> 1                e=9
265: 2 ==> 2                e=10
266: 2 ==> 3                e=11

268: 3 ==> 0                e=12
269: 3 ==> 1                e=13
270: 3 ==> 2                e=14
271: 3 ==> 3                e=15

273: If we require that proc A sends to proc B, then the SEND tag index will be given by
274:   N * rank(A) + rank(B) + offset
275: If we require that proc A will receive from proc B, then the RECV tag index will be given by
276:   N * rank(B) + rank(A) + offset

278: */
279: static void _get_tags(PetscInt counter, PetscMPIInt N, PetscMPIInt r0,PetscMPIInt r1, PetscMPIInt *_st, PetscMPIInt *_rt)
280: {
281:   PetscMPIInt st,rt;

283:   st = N*r0 + r1   +   N*N*counter;
284:   rt = N*r1 + r0   +   N*N*counter;
285:   *_st = st;
286:   *_rt = rt;
287: }

289: /*
290: Makes the communication map symmetric
291: */
292: PetscErrorCode _DMSwarmDataExCompleteCommunicationMap(MPI_Comm comm,PetscMPIInt n,PetscMPIInt proc_neighbours[],PetscMPIInt *n_new,PetscMPIInt **proc_neighbours_new)
293: {
294:   Mat               A;
295:   PetscInt          i,j,nc;
296:   PetscInt          n_, *proc_neighbours_;
297:   PetscInt          rank_;
298:   PetscMPIInt       size,  rank;
299:   PetscScalar       *vals;
300:   const PetscInt    *cols;
301:   const PetscScalar *red_vals;
302:   PetscMPIInt       _n_new, *_proc_neighbours_new;
303:   PetscErrorCode    ierr;

306:   n_ = n;
307:   PetscMalloc(sizeof(PetscInt) * n_, &proc_neighbours_);
308:   for (i = 0; i < n_; ++i) {
309:     proc_neighbours_[i] = proc_neighbours[i];
310:   }
311:   MPI_Comm_size(comm,&size);
312:   MPI_Comm_rank(comm,&rank);
313:   rank_ = rank;

315:   MatCreate(comm,&A);
316:   MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,size,size);
317:   MatSetType(A,MATAIJ);
318:   MatSeqAIJSetPreallocation(A,1,NULL);
319:   MatMPIAIJSetPreallocation(A,n_,NULL,n_,NULL);
320:   MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
321:   /* Build original map */
322:   PetscMalloc1(n_, &vals);
323:   for (i = 0; i < n_; ++i) {
324:     vals[i] = 1.0;
325:   }
326:   MatSetValues( A, 1,&rank_, n_,proc_neighbours_, vals, INSERT_VALUES );
327:   MatAssemblyBegin(A,MAT_FLUSH_ASSEMBLY);
328:   MatAssemblyEnd(A,MAT_FLUSH_ASSEMBLY);
329:   /* Now force all other connections if they are not already there */
330:   /* It's more efficient to do them all at once */
331:   for (i = 0; i < n_; ++i) {
332:     vals[i] = 2.0;
333:   }
334:   MatSetValues( A, n_,proc_neighbours_, 1,&rank_, vals, INSERT_VALUES );
335:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
336:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
337: /*
338:   PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO);
339:   MatView(A,PETSC_VIEWER_STDOUT_WORLD);
340:   PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);
341: */
342:   if ((n_new != NULL) && (proc_neighbours_new != NULL)) {
343:     MatGetRow(A, rank_, &nc, &cols, &red_vals);
344:     _n_new = (PetscMPIInt) nc;
345:     PetscMalloc1(_n_new, &_proc_neighbours_new);
346:     for (j = 0; j < nc; ++j) {
347:       _proc_neighbours_new[j] = (PetscMPIInt)cols[j];
348:     }
349:     MatRestoreRow( A, rank_, &nc, &cols, &red_vals );
350:     *n_new               = (PetscMPIInt)_n_new;
351:     *proc_neighbours_new = (PetscMPIInt*)_proc_neighbours_new;
352:   }
353:   MatDestroy(&A);
354:   PetscFree(vals);
355:   PetscFree(proc_neighbours_);
356:   MPI_Barrier(comm);
357:   return(0);
358: }

360: PetscErrorCode DMSwarmDataExTopologyFinalize(DMSwarmDataEx d)
361: {
362:   PetscMPIInt    symm_nn;
363:   PetscMPIInt   *symm_procs;
364:   PetscMPIInt    r0,n,st,rt;
365:   PetscMPIInt    size;

369:   if (d->topology_status != DEOBJECT_INITIALIZED) SETERRQ(d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be intialised. Call DMSwarmDataExTopologyInitialize() first");

371:   PetscLogEventBegin(DMSWARM_DataExchangerTopologySetup,0,0,0,0);
372:   /* given infomation about all my neighbours, make map symmetric */
373:   _DMSwarmDataExCompleteCommunicationMap( d->comm,d->n_neighbour_procs,d->neighbour_procs, &symm_nn, &symm_procs );
374:   /* update my arrays */
375:   PetscFree(d->neighbour_procs);
376:   d->n_neighbour_procs = symm_nn;
377:   d->neighbour_procs   = symm_procs;
378:   /* allocates memory */
379:   if (!d->messages_to_be_sent) {PetscMalloc1(d->n_neighbour_procs+1, &d->messages_to_be_sent);}
380:   if (!d->message_offsets) {PetscMalloc1(d->n_neighbour_procs+1, &d->message_offsets);}
381:   if (!d->messages_to_be_recvieved) {PetscMalloc1(d->n_neighbour_procs+1, &d->messages_to_be_recvieved);}
382:   if (!d->pack_cnt) {PetscMalloc(sizeof(PetscInt) * d->n_neighbour_procs, &d->pack_cnt);}
383:   if (!d->_stats) {PetscMalloc(sizeof(MPI_Status) * 2*d->n_neighbour_procs, &d->_stats);}
384:   if (!d->_requests) {PetscMalloc(sizeof(MPI_Request) * 2*d->n_neighbour_procs, &d->_requests);}
385:   if (!d->send_tags) {PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->send_tags);}
386:   if (!d->recv_tags) {PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->recv_tags);}
387:   /* compute message tags */
388:   MPI_Comm_size(d->comm,&size);
389:   r0 = d->rank;
390:   for (n = 0; n < d->n_neighbour_procs; ++n) {
391:     PetscMPIInt r1 = d->neighbour_procs[n];

393:     _get_tags( d->instance, size, r0,r1, &st, &rt );
394:     d->send_tags[n] = (int)st;
395:     d->recv_tags[n] = (int)rt;
396:   }
397:   d->topology_status = DEOBJECT_FINALIZED;
398:   PetscLogEventEnd(DMSWARM_DataExchangerTopologySetup,0,0,0,0);
399:   return(0);
400: }

402: /* === Phase B === */
403: PetscErrorCode _DMSwarmDataExConvertProcIdToLocalIndex(DMSwarmDataEx de,PetscMPIInt proc_id,PetscMPIInt *local)
404: {
405:   PetscMPIInt i,np;

408:   np = de->n_neighbour_procs;
409:   *local = -1;
410:   for (i = 0; i < np; ++i) {
411:     if (proc_id == de->neighbour_procs[i]) {
412:       *local = i;
413:       break;
414:     }
415:   }
416:   return(0);
417: }

419: PetscErrorCode DMSwarmDataExInitializeSendCount(DMSwarmDataEx de)
420: {
421:   PetscMPIInt    i;

425:   if (de->topology_status != DEOBJECT_FINALIZED) SETERRQ(de->comm, PETSC_ERR_ORDER, "Topology not finalized");
426:   PetscLogEventBegin(DMSWARM_DataExchangerSendCount,0,0,0,0);
427:   de->message_lengths_status = DEOBJECT_INITIALIZED;
428:   for (i = 0; i < de->n_neighbour_procs; ++i) {
429:     de->messages_to_be_sent[i] = 0;
430:   }
431:   return(0);
432: }

434: /*
435: 1) only allows counters to be set on neighbouring cpus
436: */
437: PetscErrorCode DMSwarmDataExAddToSendCount(DMSwarmDataEx de,const PetscMPIInt proc_id,const PetscInt count)
438: {
439:   PetscMPIInt    local_val;

443:   if (de->message_lengths_status == DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths have been defined. To modify these call DMSwarmDataExInitializeSendCount() first" );
444:   else if (de->message_lengths_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first" );
445: 
446:   _DMSwarmDataExConvertProcIdToLocalIndex( de, proc_id, &local_val );
447:   if (local_val == -1) SETERRQ1( PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,"Proc %d is not a valid neighbour rank", (int)proc_id );
448: 
449:   de->messages_to_be_sent[local_val] = de->messages_to_be_sent[local_val] + count;
450:   return(0);
451: }

453: PetscErrorCode DMSwarmDataExFinalizeSendCount(DMSwarmDataEx de)
454: {
456: 
458:   if (de->message_lengths_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first" );
459: 
460:   de->message_lengths_status = DEOBJECT_FINALIZED;
461:   PetscLogEventEnd(DMSWARM_DataExchangerSendCount,0,0,0,0);
462:   return(0);
463: }

465: /* === Phase C === */
466: /*
467:  * zero out all send counts
468:  * free send and recv buffers
469:  * zeros out message length
470:  * zeros out all counters
471:  * zero out packed data counters
472: */
473: PetscErrorCode _DMSwarmDataExInitializeTmpStorage(DMSwarmDataEx de)
474: {
475:   PetscMPIInt    i, np;

479:   /*if (de->n_neighbour_procs < 0) SETERRQ( PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of neighbour procs < 0");
480:   */
481:   /*
482:   if (!de->neighbour_procs) SETERRQ( PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Neighbour proc list is NULL" );
483:   */
484:   np = de->n_neighbour_procs;
485:   for (i = 0; i < np; ++i) {
486:     /*        de->messages_to_be_sent[i] = -1; */
487:     de->messages_to_be_recvieved[i] = -1;
488:   }
489:   PetscFree(de->send_message);
490:   PetscFree(de->recv_message);
491:   return(0);
492: }

494: /*
495: *) Zeros out pack data counters
496: *) Ensures mesaage length is set
497: *) Checks send counts properly initialized
498: *) allocates space for pack data
499: */
500: PetscErrorCode DMSwarmDataExPackInitialize(DMSwarmDataEx de,size_t unit_message_size)
501: {
502:   PetscMPIInt    i,np;
503:   PetscInt       total;

507:   if (de->topology_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Topology not finalized" );
508:   if (de->message_lengths_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths not finalized" );
509:   PetscLogEventBegin(DMSWARM_DataExchangerPack,0,0,0,0);
510:   de->packer_status = DEOBJECT_INITIALIZED;
511:   _DMSwarmDataExInitializeTmpStorage(de);
512:   np = de->n_neighbour_procs;
513:   de->unit_message_size = unit_message_size;
514:   total = 0;
515:   for (i = 0; i < np; ++i) {
516:     if (de->messages_to_be_sent[i] == -1) {
517:       PetscMPIInt proc_neighour = de->neighbour_procs[i];
518:       SETERRQ1( PETSC_COMM_SELF, PETSC_ERR_ORDER, "Messages_to_be_sent[neighbour_proc=%d] is un-initialised. Call DMSwarmDataExSetSendCount() first", (int)proc_neighour );
519:     }
520:     total = total + de->messages_to_be_sent[i];
521:   }
522:   /* create space for the data to be sent */
523:   PetscMalloc(unit_message_size * (total + 1), &de->send_message);
524:   /* initialize memory */
525:   PetscMemzero(de->send_message, unit_message_size * (total + 1));
526:   /* set total items to send */
527:   de->send_message_length = total;
528:   de->message_offsets[0] = 0;
529:   total = de->messages_to_be_sent[0];
530:   for (i = 1; i < np; ++i) {
531:     de->message_offsets[i] = total;
532:     total = total + de->messages_to_be_sent[i];
533:   }
534:   /* init the packer counters */
535:   de->total_pack_cnt = 0;
536:   for (i = 0; i < np; ++i) {
537:     de->pack_cnt[i] = 0;
538:   }
539:   return(0);
540: }

542: /*
543: *) Ensures data gets been packed appropriately and no overlaps occur
544: */
545: PetscErrorCode DMSwarmDataExPackData(DMSwarmDataEx de,PetscMPIInt proc_id,PetscInt n,void *data)
546: {
547:   PetscMPIInt    local;
548:   PetscInt       insert_location;
549:   void           *dest;

553:   if (de->packer_status == DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Packed data have been defined. To modify these call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first" );
554:   else if (de->packer_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Packed data must be defined. Call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first" );
555: 
556:   if (!de->send_message) SETERRQ( de->comm, PETSC_ERR_ORDER, "send_message is not initialized. Call DMSwarmDataExPackInitialize() first" );
557:   _DMSwarmDataExConvertProcIdToLocalIndex( de, proc_id, &local );
558:   if (local == -1) SETERRQ1( PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "proc_id %d is not registered neighbour", (int)proc_id );
559:   if (n+de->pack_cnt[local] > de->messages_to_be_sent[local]) SETERRQ3( PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to pack too many entries to be sent to proc %d. Space requested = %D: Attempt to insert %D",
560:               (int)proc_id, de->messages_to_be_sent[local], n+de->pack_cnt[local] );

562:   /* copy memory */
563:   insert_location = de->message_offsets[local] + de->pack_cnt[local];
564:   dest = ((char*)de->send_message) + de->unit_message_size*insert_location;
565:   PetscMemcpy(dest, data, de->unit_message_size * n);
566:   /* increment counter */
567:   de->pack_cnt[local] = de->pack_cnt[local] + n;
568:   return(0);
569: }

571: /*
572: *) Ensures all data has been packed
573: */
574: PetscErrorCode DMSwarmDataExPackFinalize(DMSwarmDataEx de)
575: {
576:   PetscMPIInt i,np;
577:   PetscInt    total;

581:   if (de->packer_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Packer has not been initialized. Must call DMSwarmDataExPackInitialize() first." );
582:   np = de->n_neighbour_procs;
583:   for (i = 0; i < np; ++i) {
584:     if (de->pack_cnt[i] != de->messages_to_be_sent[i]) SETERRQ3( PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not all messages for neighbour[%d] have been packed. Expected %D : Inserted %D",
585:                 (int)de->neighbour_procs[i], de->messages_to_be_sent[i], de->pack_cnt[i] );
586:   }
587:   /* init */
588:   for (i = 0; i < np; ++i) {
589:     de->messages_to_be_recvieved[i] = -1;
590:   }
591:   /* figure out the recv counts here */
592:   for (i = 0; i < np; ++i) {
593:     MPI_Isend(&de->messages_to_be_sent[i], 1, MPIU_INT, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i]);
594:   }
595:   for (i = 0; i < np; ++i) {
596:     MPI_Irecv(&de->messages_to_be_recvieved[i], 1, MPIU_INT, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np+i]);
597:   }
598:   MPI_Waitall(2*np, de->_requests, de->_stats);
599:   /* create space for the data to be recvieved */
600:   total = 0;
601:   for (i = 0; i < np; ++i) {
602:     total = total + de->messages_to_be_recvieved[i];
603:   }
604:   PetscMalloc(de->unit_message_size * (total + 1), &de->recv_message);
605:   /* initialize memory */
606:   PetscMemzero(de->recv_message, de->unit_message_size * (total + 1));
607:   /* set total items to recieve */
608:   de->recv_message_length = total;
609:   de->packer_status = DEOBJECT_FINALIZED;
610:   de->communication_status = DEOBJECT_INITIALIZED;
611:   PetscLogEventEnd(DMSWARM_DataExchangerPack,0,0,0,0);
612:   return(0);
613: }

615: /* do the actual message passing now */
616: PetscErrorCode DMSwarmDataExBegin(DMSwarmDataEx de)
617: {
618:   PetscMPIInt i,np;
619:   void       *dest;
620:   PetscInt    length;

624:   if (de->topology_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Topology not finalized" );
625:   if (de->message_lengths_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Message lengths not finalized" );
626:   if (de->packer_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Packer not finalized" );
627:   if (de->communication_status == DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Communication has already been finalized. Must call DMSwarmDataExInitialize() first." );
628:   if (!de->recv_message) SETERRQ( de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first" );
629:   PetscLogEventBegin(DMSWARM_DataExchangerBegin,0,0,0,0);
630:   np = de->n_neighbour_procs;
631:   /* == NON BLOCKING == */
632:   for (i = 0; i < np; ++i) {
633:     length = de->messages_to_be_sent[i] * de->unit_message_size;
634:     dest = ((char*)de->send_message) + de->unit_message_size * de->message_offsets[i];
635:     MPI_Isend( dest, length, MPI_CHAR, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i] );
636:   }
637:   PetscLogEventEnd(DMSWARM_DataExchangerBegin,0,0,0,0);
638:   return(0);
639: }

641: /* do the actual message passing now */
642: PetscErrorCode DMSwarmDataExEnd(DMSwarmDataEx de)
643: {
644:   PetscMPIInt  i,np;
645:   PetscInt     total;
646:   PetscInt    *message_recv_offsets;
647:   void        *dest;
648:   PetscInt     length;

652:   if (de->communication_status != DEOBJECT_INITIALIZED) SETERRQ( de->comm, PETSC_ERR_ORDER, "Communication has not been initialized. Must call DMSwarmDataExInitialize() first." );
653:   if (!de->recv_message) SETERRQ( de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first" );
654:   PetscLogEventBegin(DMSWARM_DataExchangerEnd,0,0,0,0);
655:   np = de->n_neighbour_procs;
656:   PetscMalloc1(np+1, &message_recv_offsets);
657:   message_recv_offsets[0] = 0;
658:   total = de->messages_to_be_recvieved[0];
659:   for (i = 1; i < np; ++i) {
660:     message_recv_offsets[i] = total;
661:     total = total + de->messages_to_be_recvieved[i];
662:   }
663:   /* == NON BLOCKING == */
664:   for (i = 0; i < np; ++i) {
665:     length = de->messages_to_be_recvieved[i] * de->unit_message_size;
666:     dest = ((char*)de->recv_message) + de->unit_message_size * message_recv_offsets[i];
667:     MPI_Irecv( dest, length, MPI_CHAR, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np+i] );
668:   }
669:   MPI_Waitall( 2*np, de->_requests, de->_stats );
670:   PetscFree(message_recv_offsets);
671:   de->communication_status = DEOBJECT_FINALIZED;
672:   PetscLogEventEnd(DMSWARM_DataExchangerEnd,0,0,0,0);
673:   return(0);
674: }

676: PetscErrorCode DMSwarmDataExGetSendData(DMSwarmDataEx de,PetscInt *length,void **send)
677: {
679:   if (de->packer_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being packed." );
680:   *length = de->send_message_length;
681:   *send   = de->send_message;
682:   return(0);
683: }

685: PetscErrorCode DMSwarmDataExGetRecvData(DMSwarmDataEx de,PetscInt *length,void **recv)
686: {
688:   if (de->communication_status != DEOBJECT_FINALIZED) SETERRQ( de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being sent." );
689:   *length = de->recv_message_length;
690:   *recv   = de->recv_message;
691:   return(0);
692: }

694: PetscErrorCode DMSwarmDataExTopologyGetNeighbours(DMSwarmDataEx de,PetscMPIInt *n,PetscMPIInt *neigh[])
695: {
697:   if (n)     {*n     = de->n_neighbour_procs;}
698:   if (neigh) {*neigh = de->neighbour_procs;}
699:   return(0);
700: }