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