xref: /petsc/src/dm/impls/swarm/swarm_migrate.c (revision 84467f862f2de26368b63ea79dccd665bcda30cd)
1 #include <petscsf.h>
2 #include <petscdmswarm.h>
3 #include <petscdmda.h>
4 #include <petsc/private/dmswarmimpl.h> /*I   "petscdmswarm.h"   I*/
5 #include "../src/dm/impls/swarm/data_bucket.h"
6 #include "../src/dm/impls/swarm/data_ex.h"
7 
8 /*
9  User loads desired location (MPI rank) into field DMSwarm_rank
10 
11  It should be storing the rank information as MPIInt not Int
12 */
13 PetscErrorCode DMSwarmMigrate_Push_Basic(DM dm, PetscBool remove_sent_points)
14 {
15   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
16   DMSwarmDataEx de;
17   PetscInt      p, npoints, *rankval, n_points_recv;
18   PetscMPIInt   rank, nrank;
19   void         *point_buffer, *recv_points;
20   size_t        sizeof_dmswarm_point;
21   PetscBool     debug = PETSC_FALSE;
22 
23   PetscFunctionBegin;
24   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
25 
26   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
27   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
28   PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de));
29   PetscCall(DMSwarmDataExTopologyInitialize(de));
30   for (p = 0; p < npoints; ++p) {
31     nrank = (PetscMPIInt)rankval[p];
32     if (nrank != rank) PetscCall(DMSwarmDataExTopologyAddNeighbour(de, nrank));
33   }
34   PetscCall(DMSwarmDataExTopologyFinalize(de));
35   PetscCall(DMSwarmDataExInitializeSendCount(de));
36   for (p = 0; p < npoints; p++) {
37     nrank = (PetscMPIInt)rankval[p];
38     if (nrank != rank) PetscCall(DMSwarmDataExAddToSendCount(de, nrank, 1));
39   }
40   PetscCall(DMSwarmDataExFinalizeSendCount(de));
41   PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer));
42   PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point));
43   for (p = 0; p < npoints; p++) {
44     nrank = (PetscMPIInt)rankval[p];
45     if (nrank != rank) {
46       /* copy point into buffer */
47       PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, p, point_buffer));
48       /* insert point buffer into DMSwarmDataExchanger */
49       PetscCall(DMSwarmDataExPackData(de, nrank, 1, point_buffer));
50     }
51   }
52   PetscCall(DMSwarmDataExPackFinalize(de));
53   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
54 
55   if (remove_sent_points) {
56     DMSwarmDataField gfield;
57 
58     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, DMSwarmField_rank, &gfield));
59     PetscCall(DMSwarmDataFieldGetAccess(gfield));
60     PetscCall(DMSwarmDataFieldGetEntries(gfield, (void **)&rankval));
61 
62     /* remove points which left processor */
63     PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
64     for (p = 0; p < npoints; p++) {
65       nrank = (PetscMPIInt)rankval[p];
66       if (nrank != rank) {
67         /* kill point */
68         PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
69 
70         PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, p));
71 
72         PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); /* you need to update npoints as the list size decreases! */
73         PetscCall(DMSwarmDataFieldGetAccess(gfield));
74         PetscCall(DMSwarmDataFieldGetEntries(gfield, (void **)&rankval));
75         p--; /* check replacement point */
76       }
77     }
78     PetscCall(DMSwarmDataFieldRestoreEntries(gfield, (void **)&rankval));
79     PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
80   }
81   PetscCall(DMSwarmDataExBegin(de));
82   PetscCall(DMSwarmDataExEnd(de));
83   PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points));
84   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
85   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
86   for (p = 0; p < n_points_recv; p++) {
87     void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point);
88 
89     PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p));
90   }
91   if (debug) PetscCall(DMSwarmDataExView(de));
92   PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer));
93   PetscCall(DMSwarmDataExDestroy(de));
94   PetscFunctionReturn(PETSC_SUCCESS);
95 }
96 
97 static PetscErrorCode DMSwarmMigrate_DMNeighborScatter(DM dm, DM dmcell, PetscBool remove_sent_points, PetscInt *npoints_prior_migration)
98 {
99   DM_Swarm          *swarm = (DM_Swarm *)dm->data;
100   DMSwarmDataEx      de;
101   PetscInt           r, p, npoints, *p_cellid, n_points_recv;
102   PetscMPIInt        rank, _rank;
103   const PetscMPIInt *neighbourranks;
104   void              *point_buffer, *recv_points;
105   size_t             sizeof_dmswarm_point;
106   PetscInt           nneighbors;
107   PetscMPIInt        mynneigh, *myneigh;
108 
109   PetscFunctionBegin;
110   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
111   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
112   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid));
113   PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de));
114   PetscCall(DMGetNeighbors(dmcell, &nneighbors, &neighbourranks));
115   PetscCall(DMSwarmDataExTopologyInitialize(de));
116   for (r = 0; r < nneighbors; r++) {
117     _rank = neighbourranks[r];
118     if ((_rank != rank) && (_rank > 0)) PetscCall(DMSwarmDataExTopologyAddNeighbour(de, _rank));
119   }
120   PetscCall(DMSwarmDataExTopologyFinalize(de));
121   PetscCall(DMSwarmDataExTopologyGetNeighbours(de, &mynneigh, &myneigh));
122   PetscCall(DMSwarmDataExInitializeSendCount(de));
123   for (p = 0; p < npoints; p++) {
124     if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) {
125       for (r = 0; r < mynneigh; r++) {
126         _rank = myneigh[r];
127         PetscCall(DMSwarmDataExAddToSendCount(de, _rank, 1));
128       }
129     }
130   }
131   PetscCall(DMSwarmDataExFinalizeSendCount(de));
132   PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer));
133   PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point));
134   for (p = 0; p < npoints; p++) {
135     if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) {
136       for (r = 0; r < mynneigh; r++) {
137         _rank = myneigh[r];
138         /* copy point into buffer */
139         PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, p, point_buffer));
140         /* insert point buffer into DMSwarmDataExchanger */
141         PetscCall(DMSwarmDataExPackData(de, _rank, 1, point_buffer));
142       }
143     }
144   }
145   PetscCall(DMSwarmDataExPackFinalize(de));
146   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid));
147   if (remove_sent_points) {
148     DMSwarmDataField PField;
149 
150     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, DMSwarmPICField_cellid, &PField));
151     PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid));
152     /* remove points which left processor */
153     PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
154     for (p = 0; p < npoints; p++) {
155       if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) {
156         /* kill point */
157         PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, p));
158         PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); /* you need to update npoints as the list size decreases! */
159         PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid));     /* update date point increase realloc performed */
160         p--;                                                                   /* check replacement point */
161       }
162     }
163   }
164   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, npoints_prior_migration, NULL, NULL));
165   PetscCall(DMSwarmDataExBegin(de));
166   PetscCall(DMSwarmDataExEnd(de));
167   PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points));
168   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
169   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
170   for (p = 0; p < n_points_recv; p++) {
171     void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point);
172 
173     PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p));
174   }
175   PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer));
176   PetscCall(DMSwarmDataExDestroy(de));
177   PetscFunctionReturn(PETSC_SUCCESS);
178 }
179 
180 PetscErrorCode DMSwarmMigrate_CellDMScatter(DM dm, PetscBool remove_sent_points)
181 {
182   DM_Swarm          *swarm = (DM_Swarm *)dm->data;
183   PetscInt           p, npoints, npointsg = 0, npoints2, npoints2g, *rankval, *p_cellid, npoints_prior_migration;
184   PetscSF            sfcell = NULL;
185   const PetscSFNode *LA_sfcell;
186   DM                 dmcell;
187   Vec                pos;
188   PetscBool          error_check = swarm->migrate_error_on_missing_point;
189   const char        *coordname;
190   PetscMPIInt        size, rank;
191 
192   PetscFunctionBegin;
193   PetscCall(DMSwarmGetCellDM(dm, &dmcell));
194   PetscCheck(dmcell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid if cell DM provided");
195 
196   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
197   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
198 
199 #if 1
200   {
201     PetscInt     npoints_curr, range = 0;
202     PetscSFNode *sf_cells;
203 
204     PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints_curr, NULL, NULL));
205     PetscCall(PetscMalloc1(npoints_curr, &sf_cells));
206 
207     PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid));
208     for (p = 0; p < npoints_curr; p++) {
209       sf_cells[p].rank  = 0;
210       sf_cells[p].index = p_cellid[p];
211       if (p_cellid[p] > range) range = p_cellid[p];
212     }
213     PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid));
214 
215     /* PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&sfcell)); */
216     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sfcell));
217     PetscCall(PetscSFSetGraph(sfcell, range, npoints_curr, NULL, PETSC_OWN_POINTER, sf_cells, PETSC_OWN_POINTER));
218   }
219 #endif
220 
221   PetscCall(DMSwarmGetCoordinateField(dm, &coordname));
222   PetscCall(DMSwarmCreateLocalVectorFromField(dm, coordname, &pos));
223   PetscCall(DMLocatePoints(dmcell, pos, DM_POINTLOCATION_NONE, &sfcell));
224   PetscCall(DMSwarmDestroyLocalVectorFromField(dm, coordname, &pos));
225 
226   if (error_check) PetscCall(DMSwarmGetSize(dm, &npointsg));
227   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
228   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid));
229   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
230   PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell));
231 
232   for (p = 0; p < npoints; p++) {
233     p_cellid[p] = LA_sfcell[p].index;
234     rankval[p]  = rank;
235   }
236   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
237   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid));
238   PetscCall(PetscSFDestroy(&sfcell));
239 
240   if (size > 1) {
241     PetscCall(DMSwarmMigrate_DMNeighborScatter(dm, dmcell, remove_sent_points, &npoints_prior_migration));
242   } else {
243     DMSwarmDataField PField;
244     PetscInt         npoints_curr;
245 
246     /* remove points which the domain */
247     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, DMSwarmPICField_cellid, &PField));
248     PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid));
249 
250     PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints_curr, NULL, NULL));
251     for (p = 0; p < npoints_curr; p++) {
252       if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) {
253         /* kill point */
254         PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, p));
255         PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints_curr, NULL, NULL)); /* you need to update npoints as the list size decreases! */
256         PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid));          /* update date point in case realloc performed */
257         p--;                                                                        /* check replacement point */
258       }
259     }
260     PetscCall(DMSwarmGetLocalSize(dm, &npoints_prior_migration));
261   }
262 
263   /* locate points newly received */
264   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints2, NULL, NULL));
265 
266 #if 0
267   { /* safe alternative - however this performs two point locations on: (i) the initial points set and; (ii) the (initial + received) point set */
268     PetscScalar *LA_coor;
269     PetscInt bs;
270     DMSwarmDataField PField;
271 
272     PetscCall(DMSwarmGetField(dm,coordname,&bs,NULL,(void**)&LA_coor));
273     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,bs,bs*npoints2,(const PetscScalar*)LA_coor,&pos));
274     PetscCall(DMLocatePoints(dmcell,pos,DM_POINTLOCATION_NONE,&sfcell));
275 
276     PetscCall(VecDestroy(&pos));
277     PetscCall(DMSwarmRestoreField(dm,coordname,&bs,NULL,(void**)&LA_coor));
278 
279     PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell));
280     PetscCall(DMSwarmGetField(dm,DMSwarmField_rank,NULL,NULL,(void**)&rankval));
281     for (p=0; p<npoints2; p++) {
282       rankval[p] = LA_sfcell[p].index;
283     }
284     PetscCall(PetscSFDestroy(&sfcell));
285     PetscCall(DMSwarmRestoreField(dm,DMSwarmField_rank,NULL,NULL,(void**)&rankval));
286 
287     /* remove points which left processor */
288     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db,DMSwarmField_rank,&PField));
289     PetscCall(DMSwarmDataFieldGetEntries(PField,(void**)&rankval));
290 
291     PetscCall(DMSwarmDataBucketGetSizes(swarm->db,&npoints2,NULL,NULL));
292     for (p=0; p<npoints2; p++) {
293       if (rankval[p] == DMLOCATEPOINT_POINT_NOT_FOUND) {
294         /* kill point */
295         PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db,p));
296         PetscCall(DMSwarmDataBucketGetSizes(swarm->db,&npoints2,NULL,NULL)); /* you need to update npoints as the list size decreases! */
297         PetscCall(DMSwarmDataFieldGetEntries(PField,(void**)&rankval)); /* update date point increase realloc performed */
298         p--; /* check replacement point */
299       }
300     }
301   }
302 #endif
303 
304   { /* perform two point locations: (i) on the initial points set prior to communication; and (ii) on the new (received) points */
305     PetscScalar     *LA_coor;
306     PetscInt         npoints_from_neighbours, bs;
307     DMSwarmDataField PField;
308 
309     npoints_from_neighbours = npoints2 - npoints_prior_migration;
310 
311     PetscCall(DMSwarmGetField(dm, coordname, &bs, NULL, (void **)&LA_coor));
312     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, bs, bs * npoints_from_neighbours, (const PetscScalar *)&LA_coor[bs * npoints_prior_migration], &pos));
313 
314     PetscCall(DMLocatePoints(dmcell, pos, DM_POINTLOCATION_NONE, &sfcell));
315 
316     PetscCall(VecDestroy(&pos));
317     PetscCall(DMSwarmRestoreField(dm, coordname, &bs, NULL, (void **)&LA_coor));
318 
319     PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell));
320     PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
321     PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid));
322     for (p = 0; p < npoints_from_neighbours; p++) {
323       rankval[npoints_prior_migration + p]  = rank;
324       p_cellid[npoints_prior_migration + p] = LA_sfcell[p].index;
325     }
326 
327     PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid));
328     PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
329     PetscCall(PetscSFDestroy(&sfcell));
330 
331     /* remove points which left processor */
332     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, DMSwarmPICField_cellid, &PField));
333     PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid));
334 
335     PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints2, NULL, NULL));
336     for (p = npoints_prior_migration; p < npoints2; p++) {
337       if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) {
338         /* kill point */
339         PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, p));
340         PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints2, NULL, NULL)); /* you need to update npoints as the list size decreases! */
341         PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid));      /* update date point in case realloc performed */
342         p--;                                                                    /* check replacement point */
343       }
344     }
345   }
346 
347   /* check for error on removed points */
348   if (error_check) {
349     PetscCall(DMSwarmGetSize(dm, &npoints2g));
350     PetscCheck(npointsg == npoints2g, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Points from the DMSwarm must remain constant during migration (initial %" PetscInt_FMT " - final %" PetscInt_FMT ")", npointsg, npoints2g);
351   }
352   PetscFunctionReturn(PETSC_SUCCESS);
353 }
354 
355 PetscErrorCode DMSwarmMigrate_CellDMExact(DM dm, PetscBool remove_sent_points)
356 {
357   PetscFunctionBegin;
358   PetscFunctionReturn(PETSC_SUCCESS);
359 }
360 
361 /*
362  Redundant as this assumes points can only be sent to a single rank
363 */
364 PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize)
365 {
366   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
367   DMSwarmDataEx de;
368   PetscInt      p, npoints, *rankval, n_points_recv;
369   PetscMPIInt   rank, nrank, negrank;
370   void         *point_buffer, *recv_points;
371   size_t        sizeof_dmswarm_point;
372 
373   PetscFunctionBegin;
374   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
375   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
376   *globalsize = npoints;
377   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
378   PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de));
379   PetscCall(DMSwarmDataExTopologyInitialize(de));
380   for (p = 0; p < npoints; p++) {
381     negrank = (PetscMPIInt)rankval[p];
382     if (negrank < 0) {
383       nrank = -negrank - 1;
384       PetscCall(DMSwarmDataExTopologyAddNeighbour(de, nrank));
385     }
386   }
387   PetscCall(DMSwarmDataExTopologyFinalize(de));
388   PetscCall(DMSwarmDataExInitializeSendCount(de));
389   for (p = 0; p < npoints; p++) {
390     negrank = (PetscMPIInt)rankval[p];
391     if (negrank < 0) {
392       nrank = -negrank - 1;
393       PetscCall(DMSwarmDataExAddToSendCount(de, nrank, 1));
394     }
395   }
396   PetscCall(DMSwarmDataExFinalizeSendCount(de));
397   PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer));
398   PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point));
399   for (p = 0; p < npoints; p++) {
400     negrank = (PetscMPIInt)rankval[p];
401     if (negrank < 0) {
402       nrank      = -negrank - 1;
403       rankval[p] = nrank;
404       /* copy point into buffer */
405       PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, p, point_buffer));
406       /* insert point buffer into DMSwarmDataExchanger */
407       PetscCall(DMSwarmDataExPackData(de, nrank, 1, point_buffer));
408       rankval[p] = negrank;
409     }
410   }
411   PetscCall(DMSwarmDataExPackFinalize(de));
412   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
413   PetscCall(DMSwarmDataExBegin(de));
414   PetscCall(DMSwarmDataExEnd(de));
415   PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points));
416   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
417   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
418   for (p = 0; p < n_points_recv; p++) {
419     void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point);
420 
421     PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p));
422   }
423   PetscCall(DMSwarmDataExView(de));
424   PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer));
425   PetscCall(DMSwarmDataExDestroy(de));
426   PetscFunctionReturn(PETSC_SUCCESS);
427 }
428 
429 typedef struct {
430   PetscMPIInt owner_rank;
431   PetscReal   min[3], max[3];
432 } CollectBBox;
433 
434 PETSC_EXTERN PetscErrorCode DMSwarmCollect_DMDABoundingBox(DM dm, PetscInt *globalsize)
435 {
436   DM_Swarm          *swarm = (DM_Swarm *)dm->data;
437   DMSwarmDataEx      de;
438   PetscInt           p, pk, npoints, *rankval, n_points_recv, n_bbox_recv, dim, neighbour_cells;
439   PetscMPIInt        rank, nrank;
440   void              *point_buffer, *recv_points;
441   size_t             sizeof_dmswarm_point, sizeof_bbox_ctx;
442   PetscBool          isdmda;
443   CollectBBox       *bbox, *recv_bbox;
444   const PetscMPIInt *dmneighborranks;
445   DM                 dmcell;
446 
447   PetscFunctionBegin;
448   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
449 
450   PetscCall(DMSwarmGetCellDM(dm, &dmcell));
451   PetscCheck(dmcell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid if cell DM provided");
452   isdmda = PETSC_FALSE;
453   PetscCall(PetscObjectTypeCompare((PetscObject)dmcell, DMDA, &isdmda));
454   PetscCheck(isdmda, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only DMDA support for CollectBoundingBox");
455 
456   PetscCall(DMGetDimension(dm, &dim));
457   sizeof_bbox_ctx = sizeof(CollectBBox);
458   PetscCall(PetscMalloc1(1, &bbox));
459   bbox->owner_rank = rank;
460 
461   /* compute the bounding box based on the overlapping / stenctil size */
462   {
463     Vec lcoor;
464 
465     PetscCall(DMGetCoordinatesLocal(dmcell, &lcoor));
466     if (dim >= 1) {
467       PetscCall(VecStrideMin(lcoor, 0, NULL, &bbox->min[0]));
468       PetscCall(VecStrideMax(lcoor, 0, NULL, &bbox->max[0]));
469     }
470     if (dim >= 2) {
471       PetscCall(VecStrideMin(lcoor, 1, NULL, &bbox->min[1]));
472       PetscCall(VecStrideMax(lcoor, 1, NULL, &bbox->max[1]));
473     }
474     if (dim == 3) {
475       PetscCall(VecStrideMin(lcoor, 2, NULL, &bbox->min[2]));
476       PetscCall(VecStrideMax(lcoor, 2, NULL, &bbox->max[2]));
477     }
478   }
479   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
480   *globalsize = npoints;
481   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
482   PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de));
483   /* use DMDA neighbours */
484   PetscCall(DMDAGetNeighbors(dmcell, &dmneighborranks));
485   if (dim == 1) {
486     neighbour_cells = 3;
487   } else if (dim == 2) {
488     neighbour_cells = 9;
489   } else {
490     neighbour_cells = 27;
491   }
492   PetscCall(DMSwarmDataExTopologyInitialize(de));
493   for (p = 0; p < neighbour_cells; p++) {
494     if ((dmneighborranks[p] >= 0) && (dmneighborranks[p] != rank)) PetscCall(DMSwarmDataExTopologyAddNeighbour(de, dmneighborranks[p]));
495   }
496   PetscCall(DMSwarmDataExTopologyFinalize(de));
497   PetscCall(DMSwarmDataExInitializeSendCount(de));
498   for (p = 0; p < neighbour_cells; p++) {
499     if ((dmneighborranks[p] >= 0) && (dmneighborranks[p] != rank)) PetscCall(DMSwarmDataExAddToSendCount(de, dmneighborranks[p], 1));
500   }
501   PetscCall(DMSwarmDataExFinalizeSendCount(de));
502   /* send bounding boxes */
503   PetscCall(DMSwarmDataExPackInitialize(de, sizeof_bbox_ctx));
504   for (p = 0; p < neighbour_cells; p++) {
505     nrank = dmneighborranks[p];
506     if ((nrank >= 0) && (nrank != rank)) {
507       /* insert bbox buffer into DMSwarmDataExchanger */
508       PetscCall(DMSwarmDataExPackData(de, nrank, 1, bbox));
509     }
510   }
511   PetscCall(DMSwarmDataExPackFinalize(de));
512   /* recv bounding boxes */
513   PetscCall(DMSwarmDataExBegin(de));
514   PetscCall(DMSwarmDataExEnd(de));
515   PetscCall(DMSwarmDataExGetRecvData(de, &n_bbox_recv, (void **)&recv_bbox));
516   /*  Wrong, should not be using PETSC_COMM_WORLD */
517   for (p = 0; p < n_bbox_recv; p++) {
518     PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[rank %d]: box from %d : range[%+1.4e,%+1.4e]x[%+1.4e,%+1.4e]\n", rank, recv_bbox[p].owner_rank, (double)recv_bbox[p].min[0], (double)recv_bbox[p].max[0], (double)recv_bbox[p].min[1],
519                                       (double)recv_bbox[p].max[1]));
520   }
521   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, stdout));
522   /* of course this is stupid as this "generic" function should have a better way to know what the coordinates are called */
523   PetscCall(DMSwarmDataExInitializeSendCount(de));
524   for (pk = 0; pk < n_bbox_recv; pk++) {
525     PetscReal *array_x, *array_y;
526 
527     PetscCall(DMSwarmGetField(dm, "coorx", NULL, NULL, (void **)&array_x));
528     PetscCall(DMSwarmGetField(dm, "coory", NULL, NULL, (void **)&array_y));
529     for (p = 0; p < npoints; p++) {
530       if ((array_x[p] >= recv_bbox[pk].min[0]) && (array_x[p] <= recv_bbox[pk].max[0])) {
531         if ((array_y[p] >= recv_bbox[pk].min[1]) && (array_y[p] <= recv_bbox[pk].max[1])) PetscCall(DMSwarmDataExAddToSendCount(de, recv_bbox[pk].owner_rank, 1));
532       }
533     }
534     PetscCall(DMSwarmRestoreField(dm, "coory", NULL, NULL, (void **)&array_y));
535     PetscCall(DMSwarmRestoreField(dm, "coorx", NULL, NULL, (void **)&array_x));
536   }
537   PetscCall(DMSwarmDataExFinalizeSendCount(de));
538   PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer));
539   PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point));
540   for (pk = 0; pk < n_bbox_recv; pk++) {
541     PetscReal *array_x, *array_y;
542 
543     PetscCall(DMSwarmGetField(dm, "coorx", NULL, NULL, (void **)&array_x));
544     PetscCall(DMSwarmGetField(dm, "coory", NULL, NULL, (void **)&array_y));
545     for (p = 0; p < npoints; p++) {
546       if ((array_x[p] >= recv_bbox[pk].min[0]) && (array_x[p] <= recv_bbox[pk].max[0])) {
547         if ((array_y[p] >= recv_bbox[pk].min[1]) && (array_y[p] <= recv_bbox[pk].max[1])) {
548           /* copy point into buffer */
549           PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, p, point_buffer));
550           /* insert point buffer into DMSwarmDataExchanger */
551           PetscCall(DMSwarmDataExPackData(de, recv_bbox[pk].owner_rank, 1, point_buffer));
552         }
553       }
554     }
555     PetscCall(DMSwarmRestoreField(dm, "coory", NULL, NULL, (void **)&array_y));
556     PetscCall(DMSwarmRestoreField(dm, "coorx", NULL, NULL, (void **)&array_x));
557   }
558   PetscCall(DMSwarmDataExPackFinalize(de));
559   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
560   PetscCall(DMSwarmDataExBegin(de));
561   PetscCall(DMSwarmDataExEnd(de));
562   PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points));
563   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
564   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
565   for (p = 0; p < n_points_recv; p++) {
566     void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point);
567 
568     PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p));
569   }
570   PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer));
571   PetscCall(PetscFree(bbox));
572   PetscCall(DMSwarmDataExView(de));
573   PetscCall(DMSwarmDataExDestroy(de));
574   PetscFunctionReturn(PETSC_SUCCESS);
575 }
576 
577 /* General collection when no order, or neighbour information is provided */
578 /*
579  User provides context and collect() method
580  Broadcast user context
581 
582  for each context / rank {
583    collect(swarm,context,n,list)
584  }
585 */
586 PETSC_EXTERN PetscErrorCode DMSwarmCollect_General(DM dm, PetscErrorCode (*collect)(DM, void *, PetscInt *, PetscInt **), size_t ctx_size, void *ctx, PetscInt *globalsize)
587 {
588   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
589   DMSwarmDataEx de;
590   PetscInt      p, npoints, n_points_recv;
591   PetscMPIInt   size, rank, len;
592   void         *point_buffer, *recv_points;
593   void         *ctxlist;
594   PetscInt     *n2collect, **collectlist;
595   size_t        sizeof_dmswarm_point;
596 
597   PetscFunctionBegin;
598   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
599   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
600   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
601   *globalsize = npoints;
602   /* Broadcast user context */
603   PetscCall(PetscMPIIntCast(ctx_size, &len));
604   PetscCall(PetscMalloc(ctx_size * size, &ctxlist));
605   PetscCallMPI(MPI_Allgather(ctx, len, MPI_CHAR, ctxlist, len, MPI_CHAR, PetscObjectComm((PetscObject)dm)));
606   PetscCall(PetscMalloc1(size, &n2collect));
607   PetscCall(PetscMalloc1(size, &collectlist));
608   for (PetscMPIInt r = 0; r < size; r++) {
609     PetscInt  _n2collect;
610     PetscInt *_collectlist;
611     void     *_ctx_r;
612 
613     _n2collect   = 0;
614     _collectlist = NULL;
615     if (r != rank) { /* don't collect data from yourself */
616       _ctx_r = (void *)((char *)ctxlist + r * ctx_size);
617       PetscCall(collect(dm, _ctx_r, &_n2collect, &_collectlist));
618     }
619     n2collect[r]   = _n2collect;
620     collectlist[r] = _collectlist;
621   }
622   PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de));
623   /* Define topology */
624   PetscCall(DMSwarmDataExTopologyInitialize(de));
625   for (PetscMPIInt r = 0; r < size; r++) {
626     if (n2collect[r] > 0) PetscCall(DMSwarmDataExTopologyAddNeighbour(de, (PetscMPIInt)r));
627   }
628   PetscCall(DMSwarmDataExTopologyFinalize(de));
629   /* Define send counts */
630   PetscCall(DMSwarmDataExInitializeSendCount(de));
631   for (PetscMPIInt r = 0; r < size; r++) {
632     if (n2collect[r] > 0) PetscCall(DMSwarmDataExAddToSendCount(de, r, n2collect[r]));
633   }
634   PetscCall(DMSwarmDataExFinalizeSendCount(de));
635   /* Pack data */
636   PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer));
637   PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point));
638   for (PetscMPIInt r = 0; r < size; r++) {
639     for (p = 0; p < n2collect[r]; p++) {
640       PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, collectlist[r][p], point_buffer));
641       /* insert point buffer into the data exchanger */
642       PetscCall(DMSwarmDataExPackData(de, r, 1, point_buffer));
643     }
644   }
645   PetscCall(DMSwarmDataExPackFinalize(de));
646   /* Scatter */
647   PetscCall(DMSwarmDataExBegin(de));
648   PetscCall(DMSwarmDataExEnd(de));
649   /* Collect data in DMSwarm container */
650   PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points));
651   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
652   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
653   for (p = 0; p < n_points_recv; p++) {
654     void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point);
655 
656     PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p));
657   }
658   /* Release memory */
659   for (PetscMPIInt r = 0; r < size; r++) {
660     if (collectlist[r]) PetscCall(PetscFree(collectlist[r]));
661   }
662   PetscCall(PetscFree(collectlist));
663   PetscCall(PetscFree(n2collect));
664   PetscCall(PetscFree(ctxlist));
665   PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer));
666   PetscCall(DMSwarmDataExView(de));
667   PetscCall(DMSwarmDataExDestroy(de));
668   PetscFunctionReturn(PETSC_SUCCESS);
669 }
670 
671 /*@
672   DMSwarmGetMigrateType - Get the style of point migration
673 
674   Logically Collective
675 
676   Input Parameter:
677 . dm - the `DMSWARM`
678 
679   Output Parameter:
680 . mtype - The migration type, see `DMSwarmMigrateType`
681 
682   Level: intermediate
683 
684 .seealso: `DM`, `DMSWARM`, `DMSwarmMigrateType`, `DMSwarmMigrate()`
685 @*/
686 PetscErrorCode DMSwarmGetMigrateType(DM dm, DMSwarmMigrateType *mtype)
687 {
688   PetscFunctionBegin;
689   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
690   PetscAssertPointer(mtype, 2);
691   *mtype = ((DM_Swarm *)dm->data)->migrate_type;
692   PetscFunctionReturn(PETSC_SUCCESS);
693 }
694 
695 /*@
696   DMSwarmSetMigrateType - Set the style of point migration
697 
698   Logically Collective
699 
700   Input Parameters:
701 + dm    - the `DMSWARM`
702 - mtype - The migration type, see `DMSwarmMigrateType`
703 
704   Level: intermediate
705 
706 .seealso: `DM`, `DMSWARM`, `DMSwarmMigrateType`, `DMSwarmGetMigrateType()`, `DMSwarmMigrate()`
707 @*/
708 PetscErrorCode DMSwarmSetMigrateType(DM dm, DMSwarmMigrateType mtype)
709 {
710   PetscFunctionBegin;
711   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
712   PetscValidLogicalCollectiveInt(dm, mtype, 2);
713   ((DM_Swarm *)dm->data)->migrate_type = mtype;
714   PetscFunctionReturn(PETSC_SUCCESS);
715 }
716