Actual source code: data_ex.c
petsc-3.10.5 2019-03-28
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: }