xref: /petsc/src/dm/impls/swarm/data_ex.c (revision e91c04dfc8a52dee1965211bb1cc8e5bf775178f)
1095059a4SDave May /*
2095059a4SDave May Build a few basic tools to help with partitioned domains.
3095059a4SDave May 
4095059a4SDave May 1)
5095059a4SDave May On each processor, have a DomainExchangerTopology.
6095059a4SDave May This is a doubly-connected edge list which enumerates the
7095059a4SDave May communication paths between connected processors. By numbering
8da81f932SPierre Jolivet these paths we can always uniquely assign message identifiers.
9095059a4SDave May 
10095059a4SDave May         edge
11095059a4SDave May          10
12095059a4SDave May proc  --------->  proc
13095059a4SDave May  0    <--------    1
14095059a4SDave May          11
15095059a4SDave May         twin
16095059a4SDave May 
172d4ee042Sprj- Eg: Proc 0 send to proc 1 with message id is 10. To receive the correct
18095059a4SDave May message, proc 1 looks for the edge connected to proc 0, and then the
192d4ee042Sprj- message id comes from the twin of that edge
20095059a4SDave May 
21095059a4SDave May 2)
22095059a4SDave May A DomainExchangerArrayPacker.
23095059a4SDave May A little function which given a piece of data, will memcpy the data into
24095059a4SDave May an array (which will be sent to procs) into the correct place.
25095059a4SDave May 
26095059a4SDave May On Proc 1 we sent data to procs 0,2,3. The data is on different lengths.
27095059a4SDave May All data gets jammed into single array. Need to "jam" data into correct locations
28095059a4SDave May The Packer knows how much is to going to each processor and keeps track of the inserts
29095059a4SDave May so as to avoid ever packing TOO much into one slot, and inevatbly corrupting some memory
30095059a4SDave May 
31095059a4SDave May data to 0    data to 2       data to 3
32095059a4SDave May 
33095059a4SDave May |--------|-----------------|--|
34095059a4SDave May 
35095059a4SDave May User has to unpack message themselves. I can get you the pointer for each i
36095059a4SDave May entry, but you'll have to cast it to the appropriate data type.
37095059a4SDave May 
38095059a4SDave May Phase A: Build topology
39095059a4SDave May 
40095059a4SDave May Phase B: Define message lengths
41095059a4SDave May 
42095059a4SDave May Phase C: Pack data
43095059a4SDave May 
44095059a4SDave May Phase D: Send data
45095059a4SDave May 
462064fc68SDave May + Constructor
4777048351SPatrick Sanan DMSwarmDataExCreate()
482064fc68SDave May + Phase A
4977048351SPatrick Sanan DMSwarmDataExTopologyInitialize()
5077048351SPatrick Sanan DMSwarmDataExTopologyAddNeighbour()
5177048351SPatrick Sanan DMSwarmDataExTopologyAddNeighbour()
5277048351SPatrick Sanan DMSwarmDataExTopologyFinalize()
532064fc68SDave May + Phase B
5477048351SPatrick Sanan DMSwarmDataExZeroAllSendCount()
5577048351SPatrick Sanan DMSwarmDataExAddToSendCount()
5677048351SPatrick Sanan DMSwarmDataExAddToSendCount()
5777048351SPatrick Sanan DMSwarmDataExAddToSendCount()
582064fc68SDave May + Phase C
5977048351SPatrick Sanan DMSwarmDataExPackInitialize()
6077048351SPatrick Sanan DMSwarmDataExPackData()
6177048351SPatrick Sanan DMSwarmDataExPackData()
6277048351SPatrick Sanan DMSwarmDataExPackFinalize()
632064fc68SDave May +Phase D
6477048351SPatrick Sanan DMSwarmDataExBegin()
652064fc68SDave May  ... perform any calculations ...
6677048351SPatrick Sanan DMSwarmDataExEnd()
67095059a4SDave May 
682064fc68SDave May ... user calls any getters here ...
69095059a4SDave May 
70095059a4SDave May */
71095059a4SDave May #include <petscvec.h>
72095059a4SDave May #include <petscmat.h>
736497c311SBarry Smith #include <petsc/private/petscimpl.h>
74095059a4SDave May 
75279f676cSBarry Smith #include "../src/dm/impls/swarm/data_ex.h"
76095059a4SDave May 
77095059a4SDave May const char *status_names[] = {"initialized", "finalized", "unknown"};
78095059a4SDave May 
79ed923d71SDave May PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerTopologySetup;
80ed923d71SDave May PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerBegin;
81ed923d71SDave May PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerEnd;
82ed923d71SDave May PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerSendCount;
83ed923d71SDave May PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerPack;
84095059a4SDave May 
85d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExCreate(MPI_Comm comm, const PetscInt count, DMSwarmDataEx *ex)
86d71ae5a4SJacob Faibussowitsch {
8777048351SPatrick Sanan   DMSwarmDataEx d;
88095059a4SDave May 
89521f74f9SMatthew G. Knepley   PetscFunctionBegin;
909566063dSJacob Faibussowitsch   PetscCall(PetscNew(&d));
919566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_dup(comm, &d->comm));
929566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(d->comm, &d->rank));
93095059a4SDave May 
94095059a4SDave May   d->instance = count;
95095059a4SDave May 
96095059a4SDave May   d->topology_status        = DEOBJECT_STATE_UNKNOWN;
97095059a4SDave May   d->message_lengths_status = DEOBJECT_STATE_UNKNOWN;
98095059a4SDave May   d->packer_status          = DEOBJECT_STATE_UNKNOWN;
99095059a4SDave May   d->communication_status   = DEOBJECT_STATE_UNKNOWN;
100095059a4SDave May 
101095059a4SDave May   d->n_neighbour_procs = -1;
102095059a4SDave May   d->neighbour_procs   = NULL;
103095059a4SDave May 
104095059a4SDave May   d->messages_to_be_sent      = NULL;
105095059a4SDave May   d->message_offsets          = NULL;
106095059a4SDave May   d->messages_to_be_recvieved = NULL;
107095059a4SDave May 
10878c64234SJose E. Roman   d->unit_message_size   = (size_t)-1;
109095059a4SDave May   d->send_message        = NULL;
110095059a4SDave May   d->send_message_length = -1;
111095059a4SDave May   d->recv_message        = NULL;
112095059a4SDave May   d->recv_message_length = -1;
113095059a4SDave May   d->total_pack_cnt      = -1;
114095059a4SDave May   d->pack_cnt            = NULL;
115095059a4SDave May 
116095059a4SDave May   d->send_tags = NULL;
117095059a4SDave May   d->recv_tags = NULL;
118095059a4SDave May 
119095059a4SDave May   d->_stats    = NULL;
120095059a4SDave May   d->_requests = NULL;
121521f74f9SMatthew G. Knepley   *ex          = d;
1223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
123095059a4SDave May }
124095059a4SDave May 
125298827fbSBarry Smith /*
1269dddd249SSatish Balay     This code is horrible, who let it get into main.
127298827fbSBarry Smith 
128298827fbSBarry Smith     Should be printing to a viewer, should not be using PETSC_COMM_WORLD
129298827fbSBarry Smith 
130298827fbSBarry Smith */
131d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExView(DMSwarmDataEx d)
132d71ae5a4SJacob Faibussowitsch {
133095059a4SDave May   PetscMPIInt p;
134095059a4SDave May 
135095059a4SDave May   PetscFunctionBegin;
13663a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "DMSwarmDataEx: instance=%" PetscInt_FMT "\n", d->instance));
1379566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "  topology status:        %s \n", status_names[d->topology_status]));
1389566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "  message lengths status: %s \n", status_names[d->message_lengths_status]));
1399566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "  packer status status:   %s \n", status_names[d->packer_status]));
1409566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "  communication status:   %s \n", status_names[d->communication_status]));
141095059a4SDave May 
142095059a4SDave May   if (d->topology_status == DEOBJECT_FINALIZED) {
1439566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "  Topology:\n"));
1449566063dSJacob Faibussowitsch     PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "    [%d] neighbours: %d \n", d->rank, d->n_neighbour_procs));
14548a46eb9SPierre Jolivet     for (p = 0; p < d->n_neighbour_procs; p++) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "    [%d]   neighbour[%d] = %d \n", d->rank, p, d->neighbour_procs[p]));
1469566063dSJacob Faibussowitsch     PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, stdout));
147095059a4SDave May   }
148298827fbSBarry Smith 
149095059a4SDave May   if (d->message_lengths_status == DEOBJECT_FINALIZED) {
1509566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "  Message lengths:\n"));
1519566063dSJacob Faibussowitsch     PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "    [%d] atomic size: %ld \n", d->rank, (long int)d->unit_message_size));
152095059a4SDave May     for (p = 0; p < d->n_neighbour_procs; p++) {
15363a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "    [%d] >>>>> ( %" PetscInt_FMT " units :: tag = %d) >>>>> [%d] \n", d->rank, d->messages_to_be_sent[p], d->send_tags[p], d->neighbour_procs[p]));
154095059a4SDave May     }
155095059a4SDave May     for (p = 0; p < d->n_neighbour_procs; p++) {
15663a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "    [%d] <<<<< ( %" PetscInt_FMT " units :: tag = %d) <<<<< [%d] \n", d->rank, d->messages_to_be_recvieved[p], d->recv_tags[p], d->neighbour_procs[p]));
157095059a4SDave May     }
1589566063dSJacob Faibussowitsch     PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, stdout));
159095059a4SDave May   }
160521f74f9SMatthew G. Knepley   if (d->packer_status == DEOBJECT_FINALIZED) { }
161521f74f9SMatthew G. Knepley   if (d->communication_status == DEOBJECT_FINALIZED) { }
1623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
163095059a4SDave May }
164095059a4SDave May 
165d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExDestroy(DMSwarmDataEx d)
166d71ae5a4SJacob Faibussowitsch {
167095059a4SDave May   PetscFunctionBegin;
1689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_free(&d->comm));
1699566063dSJacob Faibussowitsch   if (d->neighbour_procs) PetscCall(PetscFree(d->neighbour_procs));
1709566063dSJacob Faibussowitsch   if (d->messages_to_be_sent) PetscCall(PetscFree(d->messages_to_be_sent));
1719566063dSJacob Faibussowitsch   if (d->message_offsets) PetscCall(PetscFree(d->message_offsets));
1729566063dSJacob Faibussowitsch   if (d->messages_to_be_recvieved) PetscCall(PetscFree(d->messages_to_be_recvieved));
1739566063dSJacob Faibussowitsch   if (d->send_message) PetscCall(PetscFree(d->send_message));
1749566063dSJacob Faibussowitsch   if (d->recv_message) PetscCall(PetscFree(d->recv_message));
1759566063dSJacob Faibussowitsch   if (d->pack_cnt) PetscCall(PetscFree(d->pack_cnt));
1769566063dSJacob Faibussowitsch   if (d->send_tags) PetscCall(PetscFree(d->send_tags));
1779566063dSJacob Faibussowitsch   if (d->recv_tags) PetscCall(PetscFree(d->recv_tags));
1789566063dSJacob Faibussowitsch   if (d->_stats) PetscCall(PetscFree(d->_stats));
1799566063dSJacob Faibussowitsch   if (d->_requests) PetscCall(PetscFree(d->_requests));
1809566063dSJacob Faibussowitsch   PetscCall(PetscFree(d));
1813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
182095059a4SDave May }
183095059a4SDave May 
184095059a4SDave May /* === Phase A === */
185095059a4SDave May 
186d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExTopologyInitialize(DMSwarmDataEx d)
187d71ae5a4SJacob Faibussowitsch {
188095059a4SDave May   PetscFunctionBegin;
189095059a4SDave May   d->topology_status   = DEOBJECT_INITIALIZED;
190095059a4SDave May   d->n_neighbour_procs = 0;
1919566063dSJacob Faibussowitsch   PetscCall(PetscFree(d->neighbour_procs));
1929566063dSJacob Faibussowitsch   PetscCall(PetscFree(d->messages_to_be_sent));
1939566063dSJacob Faibussowitsch   PetscCall(PetscFree(d->message_offsets));
1949566063dSJacob Faibussowitsch   PetscCall(PetscFree(d->messages_to_be_recvieved));
1959566063dSJacob Faibussowitsch   PetscCall(PetscFree(d->pack_cnt));
1969566063dSJacob Faibussowitsch   PetscCall(PetscFree(d->send_tags));
1979566063dSJacob Faibussowitsch   PetscCall(PetscFree(d->recv_tags));
1983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
199095059a4SDave May }
200095059a4SDave May 
201d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExTopologyAddNeighbour(DMSwarmDataEx d, const PetscMPIInt proc_id)
202d71ae5a4SJacob Faibussowitsch {
203095059a4SDave May   PetscMPIInt n, found;
204d7d19db6SBarry Smith   PetscMPIInt size;
205095059a4SDave May 
206095059a4SDave May   PetscFunctionBegin;
20708401ef6SPierre Jolivet   PetscCheck(d->topology_status != DEOBJECT_FINALIZED, d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology has been finalized. To modify or update call DMSwarmDataExTopologyInitialize() first");
208f7d195e4SLawrence Mitchell   PetscCheck(d->topology_status == DEOBJECT_INITIALIZED, d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be initialised. Call DMSwarmDataExTopologyInitialize() first");
2092064fc68SDave May 
210095059a4SDave May   /* error on negative entries */
21108401ef6SPierre Jolivet   PetscCheck(proc_id >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Trying to set proc neighbour with a rank < 0");
212095059a4SDave May   /* error on ranks larger than number of procs in communicator */
2139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(d->comm, &size));
21408401ef6SPierre Jolivet   PetscCheck(proc_id < size, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Trying to set proc neighbour %d with a rank >= size %d", proc_id, size);
2159566063dSJacob Faibussowitsch   if (d->n_neighbour_procs == 0) PetscCall(PetscMalloc1(1, &d->neighbour_procs));
216095059a4SDave May   /* check for proc_id */
217095059a4SDave May   found = 0;
218095059a4SDave May   for (n = 0; n < d->n_neighbour_procs; n++) {
219ad540459SPierre Jolivet     if (d->neighbour_procs[n] == proc_id) found = 1;
220095059a4SDave May   }
221095059a4SDave May   if (found == 0) { /* add it to list */
2229566063dSJacob Faibussowitsch     PetscCall(PetscRealloc(sizeof(PetscMPIInt) * (d->n_neighbour_procs + 1), &d->neighbour_procs));
223095059a4SDave May     d->neighbour_procs[d->n_neighbour_procs] = proc_id;
224095059a4SDave May     d->n_neighbour_procs++;
225095059a4SDave May   }
2263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
227095059a4SDave May }
228095059a4SDave May 
229095059a4SDave May /*
230095059a4SDave May counter: the index of the communication object
231095059a4SDave May N: the number of processors
232095059a4SDave May r0: rank of sender
233095059a4SDave May r1: rank of receiver
234095059a4SDave May 
235095059a4SDave May procs = { 0, 1, 2, 3 }
236095059a4SDave May 
237095059a4SDave May 0 ==> 0         e=0
238095059a4SDave May 0 ==> 1         e=1
239095059a4SDave May 0 ==> 2         e=2
240095059a4SDave May 0 ==> 3         e=3
241095059a4SDave May 
242095059a4SDave May 1 ==> 0         e=4
243095059a4SDave May 1 ==> 1         e=5
244095059a4SDave May 1 ==> 2         e=6
245095059a4SDave May 1 ==> 3         e=7
246095059a4SDave May 
247095059a4SDave May 2 ==> 0         e=8
248095059a4SDave May 2 ==> 1         e=9
249095059a4SDave May 2 ==> 2         e=10
250095059a4SDave May 2 ==> 3         e=11
251095059a4SDave May 
252095059a4SDave May 3 ==> 0         e=12
253095059a4SDave May 3 ==> 1         e=13
254095059a4SDave May 3 ==> 2         e=14
255095059a4SDave May 3 ==> 3         e=15
256095059a4SDave May 
257095059a4SDave May If we require that proc A sends to proc B, then the SEND tag index will be given by
258095059a4SDave May   N * rank(A) + rank(B) + offset
259095059a4SDave May If we require that proc A will receive from proc B, then the RECV tag index will be given by
260095059a4SDave May   N * rank(B) + rank(A) + offset
261095059a4SDave May 
262095059a4SDave May */
26352c42f6eSMatthew G. Knepley static void _get_tags(PetscInt counter, PetscMPIInt N, PetscMPIInt r0, PetscMPIInt r1, PetscMPIInt maxtag, PetscMPIInt *_st, PetscMPIInt *_rt)
264d71ae5a4SJacob Faibussowitsch {
265095059a4SDave May   PetscMPIInt st, rt;
266095059a4SDave May 
26752c42f6eSMatthew G. Knepley   st   = (N * r0 + r1 + N * N * counter) % maxtag;
26852c42f6eSMatthew G. Knepley   rt   = (N * r1 + r0 + N * N * counter) % maxtag;
269095059a4SDave May   *_st = st;
270095059a4SDave May   *_rt = rt;
271095059a4SDave May }
272095059a4SDave May 
273095059a4SDave May /*
274095059a4SDave May Makes the communication map symmetric
275095059a4SDave May */
27666976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmDataExCompleteCommunicationMap_Private(MPI_Comm comm, PetscMPIInt n, const PetscMPIInt proc_neighbours[], PetscMPIInt *n_new, PetscMPIInt **proc_neighbours_new)
277d71ae5a4SJacob Faibussowitsch {
278dcf43ee8SDave May   Mat                A;
279095059a4SDave May   PetscInt           i, j, nc;
280095059a4SDave May   PetscInt           n_, *proc_neighbours_;
281e4fbd051SBarry Smith   PetscInt           rank_;
282e4fbd051SBarry Smith   PetscMPIInt        size, rank;
283095059a4SDave May   PetscScalar       *vals;
284095059a4SDave May   const PetscInt    *cols;
285095059a4SDave May   const PetscScalar *red_vals;
286095059a4SDave May   PetscMPIInt        _n_new, *_proc_neighbours_new;
287095059a4SDave May 
288095059a4SDave May   PetscFunctionBegin;
289095059a4SDave May   n_ = n;
29066976f2fSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_, &proc_neighbours_));
291ad540459SPierre Jolivet   for (i = 0; i < n_; ++i) proc_neighbours_[i] = proc_neighbours[i];
2929566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
2939566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
294e4fbd051SBarry Smith   rank_ = rank;
295095059a4SDave May 
2969566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
2979566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, size, size));
2989566063dSJacob Faibussowitsch   PetscCall(MatSetType(A, MATAIJ));
2999566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(A, 1, NULL));
3009566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(A, n_, NULL, n_, NULL));
3019566063dSJacob Faibussowitsch   PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
302095059a4SDave May   /* Build original map */
3039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_, &vals));
304ad540459SPierre Jolivet   for (i = 0; i < n_; ++i) vals[i] = 1.0;
3059566063dSJacob Faibussowitsch   PetscCall(MatSetValues(A, 1, &rank_, n_, proc_neighbours_, vals, INSERT_VALUES));
3069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FLUSH_ASSEMBLY));
3079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FLUSH_ASSEMBLY));
308095059a4SDave May   /* Now force all other connections if they are not already there */
309095059a4SDave May   /* It's more efficient to do them all at once */
310ad540459SPierre Jolivet   for (i = 0; i < n_; ++i) vals[i] = 2.0;
3119566063dSJacob Faibussowitsch   PetscCall(MatSetValues(A, n_, proc_neighbours_, 1, &rank_, vals, INSERT_VALUES));
3129566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
3139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
3146275818cSDave May   /*
3159566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO));
3169566063dSJacob Faibussowitsch   PetscCall(MatView(A,PETSC_VIEWER_STDOUT_WORLD));
3179566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
3186275818cSDave May */
319095059a4SDave May   if ((n_new != NULL) && (proc_neighbours_new != NULL)) {
3209566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, rank_, &nc, &cols, &red_vals));
321835f2295SStefano Zampini     PetscCall(PetscMPIIntCast(nc, &_n_new));
3229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(_n_new, &_proc_neighbours_new));
323835f2295SStefano Zampini     for (j = 0; j < nc; ++j) PetscCall(PetscMPIIntCast(cols[j], &_proc_neighbours_new[j]));
3249566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, rank_, &nc, &cols, &red_vals));
325835f2295SStefano Zampini     *n_new               = _n_new;
326835f2295SStefano Zampini     *proc_neighbours_new = _proc_neighbours_new;
327095059a4SDave May   }
3289566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
3299566063dSJacob Faibussowitsch   PetscCall(PetscFree(vals));
3309566063dSJacob Faibussowitsch   PetscCall(PetscFree(proc_neighbours_));
3319566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Barrier(comm));
3323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
333095059a4SDave May }
334095059a4SDave May 
335d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExTopologyFinalize(DMSwarmDataEx d)
336d71ae5a4SJacob Faibussowitsch {
33766976f2fSJacob Faibussowitsch   PetscMPIInt symm_nn = 0, *symm_procs = NULL, r0, n, st, rt, size, *maxtag, flg;
338095059a4SDave May 
339095059a4SDave May   PetscFunctionBegin;
34008401ef6SPierre Jolivet   PetscCheck(d->topology_status == DEOBJECT_INITIALIZED, d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be initialised. Call DMSwarmDataExTopologyInitialize() first");
3412064fc68SDave May 
3429566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerTopologySetup, 0, 0, 0, 0));
343a5b23f4aSJose E. Roman   /* given information about all my neighbours, make map symmetric */
34466976f2fSJacob Faibussowitsch   PetscCall(DMSwarmDataExCompleteCommunicationMap_Private(d->comm, d->n_neighbour_procs, d->neighbour_procs, &symm_nn, &symm_procs));
345095059a4SDave May   /* update my arrays */
3469566063dSJacob Faibussowitsch   PetscCall(PetscFree(d->neighbour_procs));
347095059a4SDave May   d->n_neighbour_procs = symm_nn;
348095059a4SDave May   d->neighbour_procs   = symm_procs;
349095059a4SDave May   /* allocates memory */
3509566063dSJacob Faibussowitsch   if (!d->messages_to_be_sent) PetscCall(PetscMalloc1(d->n_neighbour_procs + 1, &d->messages_to_be_sent));
3519566063dSJacob Faibussowitsch   if (!d->message_offsets) PetscCall(PetscMalloc1(d->n_neighbour_procs + 1, &d->message_offsets));
3529566063dSJacob Faibussowitsch   if (!d->messages_to_be_recvieved) PetscCall(PetscMalloc1(d->n_neighbour_procs + 1, &d->messages_to_be_recvieved));
3539566063dSJacob Faibussowitsch   if (!d->pack_cnt) PetscCall(PetscMalloc(sizeof(PetscInt) * d->n_neighbour_procs, &d->pack_cnt));
3549566063dSJacob Faibussowitsch   if (!d->_stats) PetscCall(PetscMalloc(sizeof(MPI_Status) * 2 * d->n_neighbour_procs, &d->_stats));
3559566063dSJacob Faibussowitsch   if (!d->_requests) PetscCall(PetscMalloc(sizeof(MPI_Request) * 2 * d->n_neighbour_procs, &d->_requests));
3569566063dSJacob Faibussowitsch   if (!d->send_tags) PetscCall(PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->send_tags));
3579566063dSJacob Faibussowitsch   if (!d->recv_tags) PetscCall(PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->recv_tags));
358095059a4SDave May   /* compute message tags */
3599566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(d->comm, &size));
36052c42f6eSMatthew G. Knepley   PetscCallMPI(MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_TAG_UB, &maxtag, &flg));
36152c42f6eSMatthew G. Knepley   PetscCheck(flg, d->comm, PETSC_ERR_LIB, "MPI error: MPI_Comm_get_attr() is not returning a MPI_TAG_UB");
362095059a4SDave May   r0 = d->rank;
363521f74f9SMatthew G. Knepley   for (n = 0; n < d->n_neighbour_procs; ++n) {
364095059a4SDave May     PetscMPIInt r1 = d->neighbour_procs[n];
365095059a4SDave May 
36652c42f6eSMatthew G. Knepley     _get_tags(d->instance, size, r0, r1, *maxtag, &st, &rt);
367835f2295SStefano Zampini     d->send_tags[n] = st;
368835f2295SStefano Zampini     d->recv_tags[n] = rt;
369095059a4SDave May   }
370095059a4SDave May   d->topology_status = DEOBJECT_FINALIZED;
3719566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerTopologySetup, 0, 0, 0, 0));
3723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
373095059a4SDave May }
374095059a4SDave May 
375095059a4SDave May /* === Phase B === */
37666976f2fSJacob Faibussowitsch static PetscErrorCode _DMSwarmDataExConvertProcIdToLocalIndex(DMSwarmDataEx de, PetscMPIInt proc_id, PetscMPIInt *local)
377d71ae5a4SJacob Faibussowitsch {
378095059a4SDave May   PetscMPIInt i, np;
379095059a4SDave May 
380095059a4SDave May   PetscFunctionBegin;
381095059a4SDave May   np     = de->n_neighbour_procs;
382095059a4SDave May   *local = -1;
383521f74f9SMatthew G. Knepley   for (i = 0; i < np; ++i) {
384095059a4SDave May     if (proc_id == de->neighbour_procs[i]) {
385095059a4SDave May       *local = i;
386095059a4SDave May       break;
387095059a4SDave May     }
388095059a4SDave May   }
3893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
390095059a4SDave May }
391095059a4SDave May 
392d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExInitializeSendCount(DMSwarmDataEx de)
393d71ae5a4SJacob Faibussowitsch {
394095059a4SDave May   PetscMPIInt i;
395095059a4SDave May 
396095059a4SDave May   PetscFunctionBegin;
39708401ef6SPierre Jolivet   PetscCheck(de->topology_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Topology not finalized");
3989566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerSendCount, 0, 0, 0, 0));
399095059a4SDave May   de->message_lengths_status = DEOBJECT_INITIALIZED;
400ad540459SPierre Jolivet   for (i = 0; i < de->n_neighbour_procs; ++i) de->messages_to_be_sent[i] = 0;
4013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
402095059a4SDave May }
403095059a4SDave May 
404095059a4SDave May /*
405095059a4SDave May 1) only allows counters to be set on neighbouring cpus
406095059a4SDave May */
407d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExAddToSendCount(DMSwarmDataEx de, const PetscMPIInt proc_id, const PetscInt count)
408d71ae5a4SJacob Faibussowitsch {
409095059a4SDave May   PetscMPIInt local_val;
410095059a4SDave May 
411095059a4SDave May   PetscFunctionBegin;
41208401ef6SPierre Jolivet   PetscCheck(de->message_lengths_status != DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths have been defined. To modify these call DMSwarmDataExInitializeSendCount() first");
413f7d195e4SLawrence Mitchell   PetscCheck(de->message_lengths_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first");
4142064fc68SDave May 
4159566063dSJacob Faibussowitsch   PetscCall(_DMSwarmDataExConvertProcIdToLocalIndex(de, proc_id, &local_val));
41608401ef6SPierre Jolivet   PetscCheck(local_val != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Proc %d is not a valid neighbour rank", (int)proc_id);
4172064fc68SDave May 
418095059a4SDave May   de->messages_to_be_sent[local_val] = de->messages_to_be_sent[local_val] + count;
4193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
420095059a4SDave May }
421095059a4SDave May 
422d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExFinalizeSendCount(DMSwarmDataEx de)
423d71ae5a4SJacob Faibussowitsch {
424095059a4SDave May   PetscFunctionBegin;
42508401ef6SPierre Jolivet   PetscCheck(de->message_lengths_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first");
4262064fc68SDave May 
427095059a4SDave May   de->message_lengths_status = DEOBJECT_FINALIZED;
4289566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerSendCount, 0, 0, 0, 0));
4293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
430095059a4SDave May }
431095059a4SDave May 
432095059a4SDave May /* === Phase C === */
433095059a4SDave May /*
4345627991aSBarry Smith   zero out all send counts
4355627991aSBarry Smith   free send and recv buffers
4365627991aSBarry Smith   zeros out message length
4375627991aSBarry Smith   zeros out all counters
4385627991aSBarry Smith   zero out packed data counters
439095059a4SDave May */
44066976f2fSJacob Faibussowitsch static PetscErrorCode _DMSwarmDataExInitializeTmpStorage(DMSwarmDataEx de)
441d71ae5a4SJacob Faibussowitsch {
442095059a4SDave May   PetscMPIInt i, np;
443095059a4SDave May 
444095059a4SDave May   PetscFunctionBegin;
445095059a4SDave May   np = de->n_neighbour_procs;
446521f74f9SMatthew G. Knepley   for (i = 0; i < np; ++i) {
447095059a4SDave May     /*  de->messages_to_be_sent[i] = -1; */
448095059a4SDave May     de->messages_to_be_recvieved[i] = -1;
449095059a4SDave May   }
4509566063dSJacob Faibussowitsch   PetscCall(PetscFree(de->send_message));
4519566063dSJacob Faibussowitsch   PetscCall(PetscFree(de->recv_message));
4523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
453095059a4SDave May }
454095059a4SDave May 
455095059a4SDave May /*
4565627991aSBarry Smith    Zeros out pack data counters
4575627991aSBarry Smith    Ensures mesaage length is set
4585627991aSBarry Smith    Checks send counts properly initialized
4595627991aSBarry Smith    allocates space for pack data
460095059a4SDave May */
461d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExPackInitialize(DMSwarmDataEx de, size_t unit_message_size)
462d71ae5a4SJacob Faibussowitsch {
463095059a4SDave May   PetscMPIInt i, np;
464095059a4SDave May   PetscInt    total;
465095059a4SDave May 
466095059a4SDave May   PetscFunctionBegin;
46708401ef6SPierre Jolivet   PetscCheck(de->topology_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Topology not finalized");
46808401ef6SPierre Jolivet   PetscCheck(de->message_lengths_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths not finalized");
4699566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerPack, 0, 0, 0, 0));
470095059a4SDave May   de->packer_status = DEOBJECT_INITIALIZED;
4719566063dSJacob Faibussowitsch   PetscCall(_DMSwarmDataExInitializeTmpStorage(de));
472095059a4SDave May   np                    = de->n_neighbour_procs;
473095059a4SDave May   de->unit_message_size = unit_message_size;
474095059a4SDave May   total                 = 0;
475521f74f9SMatthew G. Knepley   for (i = 0; i < np; ++i) {
476095059a4SDave May     if (de->messages_to_be_sent[i] == -1) {
477095059a4SDave May       PetscMPIInt proc_neighour = de->neighbour_procs[i];
478835f2295SStefano Zampini       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ORDER, "Messages_to_be_sent[neighbour_proc=%d] is un-initialised. Call DMSwarmDataExSetSendCount() first", proc_neighour);
479095059a4SDave May     }
480095059a4SDave May     total = total + de->messages_to_be_sent[i];
481095059a4SDave May   }
482095059a4SDave May   /* create space for the data to be sent */
4839566063dSJacob Faibussowitsch   PetscCall(PetscMalloc(unit_message_size * (total + 1), &de->send_message));
484095059a4SDave May   /* initialize memory */
4859566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(de->send_message, unit_message_size * (total + 1)));
486095059a4SDave May   /* set total items to send */
487095059a4SDave May   de->send_message_length = total;
488095059a4SDave May   de->message_offsets[0]  = 0;
489095059a4SDave May   total                   = de->messages_to_be_sent[0];
490521f74f9SMatthew G. Knepley   for (i = 1; i < np; ++i) {
491095059a4SDave May     de->message_offsets[i] = total;
492095059a4SDave May     total                  = total + de->messages_to_be_sent[i];
493095059a4SDave May   }
494095059a4SDave May   /* init the packer counters */
495095059a4SDave May   de->total_pack_cnt = 0;
496ad540459SPierre Jolivet   for (i = 0; i < np; ++i) de->pack_cnt[i] = 0;
4973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
498095059a4SDave May }
499095059a4SDave May 
500095059a4SDave May /*
5015627991aSBarry Smith     Ensures data gets been packed appropriately and no overlaps occur
502095059a4SDave May */
503d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExPackData(DMSwarmDataEx de, PetscMPIInt proc_id, PetscInt n, void *data)
504d71ae5a4SJacob Faibussowitsch {
505095059a4SDave May   PetscMPIInt local;
506095059a4SDave May   PetscInt    insert_location;
507095059a4SDave May   void       *dest;
508095059a4SDave May 
509095059a4SDave May   PetscFunctionBegin;
51008401ef6SPierre Jolivet   PetscCheck(de->packer_status != DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Packed data have been defined. To modify these call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first");
511f7d195e4SLawrence Mitchell   PetscCheck(de->packer_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Packed data must be defined. Call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first");
5122064fc68SDave May 
51328b400f6SJacob Faibussowitsch   PetscCheck(de->send_message, de->comm, PETSC_ERR_ORDER, "send_message is not initialized. Call DMSwarmDataExPackInitialize() first");
5149566063dSJacob Faibussowitsch   PetscCall(_DMSwarmDataExConvertProcIdToLocalIndex(de, proc_id, &local));
515835f2295SStefano Zampini   PetscCheck(local != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "proc_id %d is not registered neighbour", proc_id);
516835f2295SStefano Zampini   PetscCheck(n + de->pack_cnt[local] <= de->messages_to_be_sent[local], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to pack too many entries to be sent to proc %d. Space requested = %" PetscInt_FMT ": Attempt to insert %" PetscInt_FMT, proc_id, de->messages_to_be_sent[local], n + de->pack_cnt[local]);
5172064fc68SDave May 
518095059a4SDave May   /* copy memory */
519095059a4SDave May   insert_location = de->message_offsets[local] + de->pack_cnt[local];
520095059a4SDave May   dest            = ((char *)de->send_message) + de->unit_message_size * insert_location;
5219566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(dest, data, de->unit_message_size * n));
522095059a4SDave May   /* increment counter */
523095059a4SDave May   de->pack_cnt[local] = de->pack_cnt[local] + n;
5243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
525095059a4SDave May }
526095059a4SDave May 
527095059a4SDave May /*
528095059a4SDave May *) Ensures all data has been packed
529095059a4SDave May */
530d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExPackFinalize(DMSwarmDataEx de)
531d71ae5a4SJacob Faibussowitsch {
532095059a4SDave May   PetscMPIInt i, np;
533095059a4SDave May   PetscInt    total;
534095059a4SDave May 
535095059a4SDave May   PetscFunctionBegin;
53608401ef6SPierre Jolivet   PetscCheck(de->packer_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Packer has not been initialized. Must call DMSwarmDataExPackInitialize() first.");
537095059a4SDave May   np = de->n_neighbour_procs;
538521f74f9SMatthew G. Knepley   for (i = 0; i < np; ++i) {
539835f2295SStefano Zampini     PetscCheck(de->pack_cnt[i] == de->messages_to_be_sent[i], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not all messages for neighbour[%d] have been packed. Expected %" PetscInt_FMT " : Inserted %" PetscInt_FMT, de->neighbour_procs[i], de->messages_to_be_sent[i], de->pack_cnt[i]);
540095059a4SDave May   }
541095059a4SDave May   /* init */
542ad540459SPierre Jolivet   for (i = 0; i < np; ++i) de->messages_to_be_recvieved[i] = -1;
543095059a4SDave May   /* figure out the recv counts here */
5446497c311SBarry Smith   for (i = 0; i < np; ++i) PetscCallMPI(MPIU_Isend(&de->messages_to_be_sent[i], 1, MPIU_INT, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i]));
5456497c311SBarry Smith   for (i = 0; i < np; ++i) PetscCallMPI(MPIU_Irecv(&de->messages_to_be_recvieved[i], 1, MPIU_INT, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np + i]));
5469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(2 * np, de->_requests, de->_stats));
547095059a4SDave May   /* create space for the data to be recvieved */
548095059a4SDave May   total = 0;
549ad540459SPierre Jolivet   for (i = 0; i < np; ++i) total = total + de->messages_to_be_recvieved[i];
5509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc(de->unit_message_size * (total + 1), &de->recv_message));
551095059a4SDave May   /* initialize memory */
5529566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(de->recv_message, de->unit_message_size * (total + 1)));
5532d4ee042Sprj-   /* set total items to receive */
554095059a4SDave May   de->recv_message_length  = total;
555095059a4SDave May   de->packer_status        = DEOBJECT_FINALIZED;
556095059a4SDave May   de->communication_status = DEOBJECT_INITIALIZED;
5579566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerPack, 0, 0, 0, 0));
5583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
559095059a4SDave May }
560095059a4SDave May 
5615627991aSBarry Smith /* do the actual message passing */
562d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExBegin(DMSwarmDataEx de)
563d71ae5a4SJacob Faibussowitsch {
564*e91c04dfSPierre Jolivet   PetscMPIInt i, np;
565095059a4SDave May   void       *dest;
566095059a4SDave May 
567095059a4SDave May   PetscFunctionBegin;
56808401ef6SPierre Jolivet   PetscCheck(de->topology_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Topology not finalized");
56908401ef6SPierre Jolivet   PetscCheck(de->message_lengths_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths not finalized");
57008401ef6SPierre Jolivet   PetscCheck(de->packer_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Packer not finalized");
57108401ef6SPierre Jolivet   PetscCheck(de->communication_status != DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Communication has already been finalized. Must call DMSwarmDataExInitialize() first.");
57228b400f6SJacob Faibussowitsch   PetscCheck(de->recv_message, de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first");
5739566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerBegin, 0, 0, 0, 0));
574095059a4SDave May   np = de->n_neighbour_procs;
575095059a4SDave May   /* == NON BLOCKING == */
576521f74f9SMatthew G. Knepley   for (i = 0; i < np; ++i) {
577095059a4SDave May     dest = ((char *)de->send_message) + de->unit_message_size * de->message_offsets[i];
578*e91c04dfSPierre Jolivet     PetscCallMPI(MPIU_Isend(dest, de->messages_to_be_sent[i] * de->unit_message_size, MPI_CHAR, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i]));
579095059a4SDave May   }
5809566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerBegin, 0, 0, 0, 0));
5813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
582095059a4SDave May }
583095059a4SDave May 
584095059a4SDave May /* do the actual message passing now */
585d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExEnd(DMSwarmDataEx de)
586d71ae5a4SJacob Faibussowitsch {
587*e91c04dfSPierre Jolivet   PetscMPIInt i, np;
588095059a4SDave May   PetscInt    total;
589095059a4SDave May   PetscInt   *message_recv_offsets;
590095059a4SDave May   void       *dest;
591095059a4SDave May 
592095059a4SDave May   PetscFunctionBegin;
59308401ef6SPierre Jolivet   PetscCheck(de->communication_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Communication has not been initialized. Must call DMSwarmDataExInitialize() first.");
59428b400f6SJacob Faibussowitsch   PetscCheck(de->recv_message, de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first");
5959566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerEnd, 0, 0, 0, 0));
596095059a4SDave May   np = de->n_neighbour_procs;
5979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(np + 1, &message_recv_offsets));
598095059a4SDave May   message_recv_offsets[0] = 0;
599095059a4SDave May   total                   = de->messages_to_be_recvieved[0];
600521f74f9SMatthew G. Knepley   for (i = 1; i < np; ++i) {
601095059a4SDave May     message_recv_offsets[i] = total;
602095059a4SDave May     total                   = total + de->messages_to_be_recvieved[i];
603095059a4SDave May   }
604095059a4SDave May   /* == NON BLOCKING == */
605521f74f9SMatthew G. Knepley   for (i = 0; i < np; ++i) {
606095059a4SDave May     dest = ((char *)de->recv_message) + de->unit_message_size * message_recv_offsets[i];
607*e91c04dfSPierre Jolivet     PetscCallMPI(MPIU_Irecv(dest, de->messages_to_be_recvieved[i] * de->unit_message_size, MPI_CHAR, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np + i]));
608095059a4SDave May   }
6099566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(2 * np, de->_requests, de->_stats));
6109566063dSJacob Faibussowitsch   PetscCall(PetscFree(message_recv_offsets));
611095059a4SDave May   de->communication_status = DEOBJECT_FINALIZED;
6129566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerEnd, 0, 0, 0, 0));
6133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
614095059a4SDave May }
615095059a4SDave May 
616d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExGetSendData(DMSwarmDataEx de, PetscInt *length, void **send)
617d71ae5a4SJacob Faibussowitsch {
618095059a4SDave May   PetscFunctionBegin;
61908401ef6SPierre Jolivet   PetscCheck(de->packer_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being packed.");
620095059a4SDave May   *length = de->send_message_length;
621095059a4SDave May   *send   = de->send_message;
6223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
623095059a4SDave May }
624095059a4SDave May 
625d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExGetRecvData(DMSwarmDataEx de, PetscInt *length, void **recv)
626d71ae5a4SJacob Faibussowitsch {
627095059a4SDave May   PetscFunctionBegin;
62808401ef6SPierre Jolivet   PetscCheck(de->communication_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being sent.");
629095059a4SDave May   *length = de->recv_message_length;
630095059a4SDave May   *recv   = de->recv_message;
6313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
632095059a4SDave May }
633095059a4SDave May 
634d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDataExTopologyGetNeighbours(DMSwarmDataEx de, PetscMPIInt *n, PetscMPIInt *neigh[])
635d71ae5a4SJacob Faibussowitsch {
636095059a4SDave May   PetscFunctionBegin;
637ad540459SPierre Jolivet   if (n) *n = de->n_neighbour_procs;
638ad540459SPierre Jolivet   if (neigh) *neigh = de->neighbour_procs;
6393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
640095059a4SDave May }
641