xref: /petsc/src/dm/interface/dmcoordinates.c (revision 7297401a5367aeba0c06629340b719d47d512b57)
1 #include <petsc/private/dmimpl.h> /*I      "petscdm.h"          I*/
2 
3 #include <petscdmplex.h> /* For DMProjectCoordinates() */
4 #include <petscsf.h>     /* For DMLocatePoints() */
5 
6 PetscErrorCode DMRestrictHook_Coordinates(DM dm, DM dmc, void *ctx)
7 {
8   DM  dm_coord, dmc_coord;
9   Vec coords, ccoords;
10   Mat inject;
11   PetscFunctionBegin;
12   PetscCall(DMGetCoordinateDM(dm, &dm_coord));
13   PetscCall(DMGetCoordinateDM(dmc, &dmc_coord));
14   PetscCall(DMGetCoordinates(dm, &coords));
15   PetscCall(DMGetCoordinates(dmc, &ccoords));
16   if (coords && !ccoords) {
17     PetscCall(DMCreateGlobalVector(dmc_coord, &ccoords));
18     PetscCall(PetscObjectSetName((PetscObject)ccoords, "coordinates"));
19     PetscCall(DMCreateInjection(dmc_coord, dm_coord, &inject));
20     PetscCall(MatRestrict(inject, coords, ccoords));
21     PetscCall(MatDestroy(&inject));
22     PetscCall(DMSetCoordinates(dmc, ccoords));
23     PetscCall(VecDestroy(&ccoords));
24   }
25   PetscFunctionReturn(0);
26 }
27 
28 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm, DM subdm, void *ctx)
29 {
30   DM          dm_coord, subdm_coord;
31   Vec         coords, ccoords, clcoords;
32   VecScatter *scat_i, *scat_g;
33   PetscFunctionBegin;
34   PetscCall(DMGetCoordinateDM(dm, &dm_coord));
35   PetscCall(DMGetCoordinateDM(subdm, &subdm_coord));
36   PetscCall(DMGetCoordinates(dm, &coords));
37   PetscCall(DMGetCoordinates(subdm, &ccoords));
38   if (coords && !ccoords) {
39     PetscCall(DMCreateGlobalVector(subdm_coord, &ccoords));
40     PetscCall(PetscObjectSetName((PetscObject)ccoords, "coordinates"));
41     PetscCall(DMCreateLocalVector(subdm_coord, &clcoords));
42     PetscCall(PetscObjectSetName((PetscObject)clcoords, "coordinates"));
43     PetscCall(DMCreateDomainDecompositionScatters(dm_coord, 1, &subdm_coord, NULL, &scat_i, &scat_g));
44     PetscCall(VecScatterBegin(scat_i[0], coords, ccoords, INSERT_VALUES, SCATTER_FORWARD));
45     PetscCall(VecScatterEnd(scat_i[0], coords, ccoords, INSERT_VALUES, SCATTER_FORWARD));
46     PetscCall(VecScatterBegin(scat_g[0], coords, clcoords, INSERT_VALUES, SCATTER_FORWARD));
47     PetscCall(VecScatterEnd(scat_g[0], coords, clcoords, INSERT_VALUES, SCATTER_FORWARD));
48     PetscCall(DMSetCoordinates(subdm, ccoords));
49     PetscCall(DMSetCoordinatesLocal(subdm, clcoords));
50     PetscCall(VecScatterDestroy(&scat_i[0]));
51     PetscCall(VecScatterDestroy(&scat_g[0]));
52     PetscCall(VecDestroy(&ccoords));
53     PetscCall(VecDestroy(&clcoords));
54     PetscCall(PetscFree(scat_i));
55     PetscCall(PetscFree(scat_g));
56   }
57   PetscFunctionReturn(0);
58 }
59 
60 /*@
61   DMGetCoordinateDM - Gets the `DM` that prescribes coordinate layout and scatters between global and local coordinates
62 
63   Collective on dm
64 
65   Input Parameter:
66 . dm - the `DM`
67 
68   Output Parameter:
69 . cdm - coordinate `DM`
70 
71   Level: intermediate
72 
73 .seealso: `DM`, `DMSetCoordinateDM()`, `DMSetCoordinates()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGSetCellCoordinateDM()`,
74           `DMGSetCellCoordinateDM()`
75 @*/
76 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
77 {
78   PetscFunctionBegin;
79   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
80   PetscValidPointer(cdm, 2);
81   if (!dm->coordinates[0].dm) {
82     DM cdm;
83 
84     PetscUseTypeMethod(dm, createcoordinatedm, &cdm);
85     PetscCall(PetscObjectSetName((PetscObject)cdm, "coordinateDM"));
86     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
87      * until the call to CreateCoordinateDM) */
88     PetscCall(DMDestroy(&dm->coordinates[0].dm));
89     dm->coordinates[0].dm = cdm;
90   }
91   *cdm = dm->coordinates[0].dm;
92   PetscFunctionReturn(0);
93 }
94 
95 /*@
96   DMSetCoordinateDM - Sets the `DM` that prescribes coordinate layout and scatters between global and local coordinates
97 
98   Logically Collective on dm
99 
100   Input Parameters:
101 + dm - the `DM`
102 - cdm - coordinate `DM`
103 
104   Level: intermediate
105 
106 .seealso: `DM`, `DMGetCoordinateDM()`, `DMSetCoordinates()`, `DMGetCellCoordinateDM()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`,
107           `DMGSetCellCoordinateDM()`
108 @*/
109 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
110 {
111   PetscFunctionBegin;
112   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
113   PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
114   PetscCall(PetscObjectReference((PetscObject)cdm));
115   PetscCall(DMDestroy(&dm->coordinates[0].dm));
116   dm->coordinates[0].dm = cdm;
117   PetscFunctionReturn(0);
118 }
119 
120 /*@
121   DMGetCellCoordinateDM - Gets the `DM` that prescribes cellwise coordinate layout and scatters between global and local cellwise coordinates
122 
123   Collective on dm
124 
125   Input Parameter:
126 . dm - the `DM`
127 
128   Output Parameter:
129 . cdm - cellwise coordinate `DM`, or NULL if they are not defined
130 
131   Level: intermediate
132 
133   Note:
134   Call `DMLocalizeCoordinates()` to automatically create cellwise coordinates for periodic geometries.
135 
136 .seealso: `DM`, `DMSetCellCoordinateDM()`, `DMSetCellCoordinates()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMGetCellCoordinatesLocal()`,
137           `DMLocalizeCoordinates()`, `DMSetCoordinateDM()`, `DMGetCoordinateDM()`
138 @*/
139 PetscErrorCode DMGetCellCoordinateDM(DM dm, DM *cdm)
140 {
141   PetscFunctionBegin;
142   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
143   PetscValidPointer(cdm, 2);
144   *cdm = dm->coordinates[1].dm;
145   PetscFunctionReturn(0);
146 }
147 
148 /*@
149   DMSetCellCoordinateDM - Sets the `DM` that prescribes cellwise coordinate layout and scatters between global and local cellwise coordinates
150 
151   Logically Collective on dm
152 
153   Input Parameters:
154 + dm - the `DM`
155 - cdm - cellwise coordinate `DM`
156 
157   Level: intermediate
158 
159   Note:
160   As opposed to `DMSetCoordinateDM()` these coordinates are useful for discontinous Galerkin methods since they support coordinate fields that are discontinuous at cell boundaries.
161 
162 .seealso: `DMGetCellCoordinateDM()`, `DMSetCellCoordinates()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMGetCellCoordinatesLocal()`,
163           `DMSetCoordinateDM()`, `DMGetCoordinateDM()`
164 @*/
165 PetscErrorCode DMSetCellCoordinateDM(DM dm, DM cdm)
166 {
167   PetscInt dim;
168 
169   PetscFunctionBegin;
170   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
171   if (cdm) {
172     PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
173     PetscCall(DMGetCoordinateDim(dm, &dim));
174     dm->coordinates[1].dim = dim;
175   }
176   PetscCall(PetscObjectReference((PetscObject)cdm));
177   PetscCall(DMDestroy(&dm->coordinates[1].dm));
178   dm->coordinates[1].dm = cdm;
179   PetscFunctionReturn(0);
180 }
181 
182 /*@
183   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values. For example a mesh on the surface of a sphere would have a 3 dimensional embedding space
184 
185   Not Collective
186 
187   Input Parameter:
188 . dm - The `DM` object
189 
190   Output Parameter:
191 . dim - The embedding dimension
192 
193   Level: intermediate
194 
195 .seealso: `DM`, `DMSetCoordinateDim()`, `DMGetCoordinateSection()`, `DMGetCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()`
196 @*/
197 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
198 {
199   PetscFunctionBegin;
200   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
201   PetscValidIntPointer(dim, 2);
202   if (dm->coordinates[0].dim == PETSC_DEFAULT) dm->coordinates[0].dim = dm->dim;
203   *dim = dm->coordinates[0].dim;
204   PetscFunctionReturn(0);
205 }
206 
207 /*@
208   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
209 
210   Not Collective
211 
212   Input Parameters:
213 + dm  - The `DM` object
214 - dim - The embedding dimension
215 
216   Level: intermediate
217 
218 .seealso: `DM`, `DMGetCoordinateDim()`, `DMSetCoordinateSection()`, `DMGetCoordinateSection()`, `DMGetLocalSection()`, `DMSetLocalSection()`
219 @*/
220 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
221 {
222   PetscDS  ds;
223   PetscInt Nds, n;
224 
225   PetscFunctionBegin;
226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
227   dm->coordinates[0].dim = dim;
228   if (dm->dim >= 0) {
229     PetscCall(DMGetNumDS(dm, &Nds));
230     for (n = 0; n < Nds; ++n) {
231       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds));
232       PetscCall(PetscDSSetCoordinateDimension(ds, dim));
233     }
234   }
235   PetscFunctionReturn(0);
236 }
237 
238 /*@
239   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
240 
241   Collective on dm
242 
243   Input Parameter:
244 . dm - The `DM` object
245 
246   Output Parameter:
247 . section - The `PetscSection` object
248 
249   Level: intermediate
250 
251   Note:
252   This just retrieves the local section from the coordinate `DM`. In other words,
253 .vb
254   DMGetCoordinateDM(dm, &cdm);
255   DMGetLocalSection(cdm, &section);
256 .ve
257 
258 .seealso: `DMGetCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()`
259 @*/
260 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
261 {
262   DM cdm;
263 
264   PetscFunctionBegin;
265   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
266   PetscValidPointer(section, 2);
267   PetscCall(DMGetCoordinateDM(dm, &cdm));
268   PetscCall(DMGetLocalSection(cdm, section));
269   PetscFunctionReturn(0);
270 }
271 
272 /*@
273   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
274 
275   Not Collective
276 
277   Input Parameters:
278 + dm      - The `DM` object
279 . dim     - The embedding dimension, or `PETSC_DETERMINE`
280 - section - The `PetscSection` object
281 
282   Level: intermediate
283 
284 .seealso: `DM`, `DMGetCoordinateDim()`, `DMGetCoordinateSection()`, `DMGetLocalSection()`, `DMSetLocalSection()`
285 @*/
286 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
287 {
288   DM cdm;
289 
290   PetscFunctionBegin;
291   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
292   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 3);
293   PetscCall(DMGetCoordinateDM(dm, &cdm));
294   PetscCall(DMSetLocalSection(cdm, section));
295   if (dim == PETSC_DETERMINE) {
296     PetscInt d = PETSC_DEFAULT;
297     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
298 
299     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
300     PetscCall(DMGetDimPoints(dm, 0, &vStart, &vEnd));
301     pStart = PetscMax(vStart, pStart);
302     pEnd   = PetscMin(vEnd, pEnd);
303     for (v = pStart; v < pEnd; ++v) {
304       PetscCall(PetscSectionGetDof(section, v, &dd));
305       if (dd) {
306         d = dd;
307         break;
308       }
309     }
310     if (d >= 0) PetscCall(DMSetCoordinateDim(dm, d));
311   }
312   PetscFunctionReturn(0);
313 }
314 
315 /*@
316   DMGetCellCoordinateSection - Retrieve the layout of cellwise coordinate values over the mesh.
317 
318   Collective on dm
319 
320   Input Parameter:
321 . dm - The `DM` object
322 
323   Output Parameter:
324 . section - The `PetscSection` object, or NULL if no cellwise coordinates are defined
325 
326   Level: intermediate
327 
328   Note:
329   This just retrieves the local section from the cell coordinate `DM`. In other words,
330 .vb
331   DMGetCellCoordinateDM(dm, &cdm);
332   DMGetLocalSection(cdm, &section);
333 .ve
334 
335 .seealso: `DM`, `DMGetCoordinateSection()`, `DMSetCellCoordinateSection()`, `DMGetCellCoordinateDM()`, `DMGetCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()`
336 @*/
337 PetscErrorCode DMGetCellCoordinateSection(DM dm, PetscSection *section)
338 {
339   DM cdm;
340 
341   PetscFunctionBegin;
342   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
343   PetscValidPointer(section, 2);
344   *section = NULL;
345   PetscCall(DMGetCellCoordinateDM(dm, &cdm));
346   if (cdm) PetscCall(DMGetLocalSection(cdm, section));
347   PetscFunctionReturn(0);
348 }
349 
350 /*@
351   DMSetCellCoordinateSection - Set the layout of cellwise coordinate values over the mesh.
352 
353   Not Collective
354 
355   Input Parameters:
356 + dm      - The `DM` object
357 . dim     - The embedding dimension, or `PETSC_DETERMINE`
358 - section - The `PetscSection` object for a cellwise layout
359 
360   Level: intermediate
361 
362 .seealso: `DM`, `DMGetCoordinateDim()`, `DMSetCoordinateSection()`, `DMGetCellCoordinateSection()`, `DMGetCoordinateSection()`, `DMGetCellCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()`
363 @*/
364 PetscErrorCode DMSetCellCoordinateSection(DM dm, PetscInt dim, PetscSection section)
365 {
366   DM cdm;
367 
368   PetscFunctionBegin;
369   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
370   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 3);
371   PetscCall(DMGetCellCoordinateDM(dm, &cdm));
372   PetscCheck(cdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "No DM defined for cellwise coordinates");
373   PetscCall(DMSetLocalSection(cdm, section));
374   if (dim == PETSC_DETERMINE) {
375     PetscInt d = PETSC_DEFAULT;
376     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
377 
378     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
379     PetscCall(DMGetDimPoints(dm, 0, &vStart, &vEnd));
380     pStart = PetscMax(vStart, pStart);
381     pEnd   = PetscMin(vEnd, pEnd);
382     for (v = pStart; v < pEnd; ++v) {
383       PetscCall(PetscSectionGetDof(section, v, &dd));
384       if (dd) {
385         d = dd;
386         break;
387       }
388     }
389     if (d >= 0) PetscCall(DMSetCoordinateDim(dm, d));
390   }
391   PetscFunctionReturn(0);
392 }
393 
394 /*@
395   DMGetCoordinates - Gets a global vector with the coordinates associated with the `DM`.
396 
397   Collective on dm
398 
399   Input Parameter:
400 . dm - the `DM`
401 
402   Output Parameter:
403 . c - global coordinate vector
404 
405   Level: intermediate
406 
407   Notes:
408   This is a borrowed reference, so the user should NOT destroy this vector. When the `DM` is
409   destroyed the array will no longer be valid.
410 
411   Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).
412 
413   For `DMDA`, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
414   and (x_0,y_0,z_0,x_1,y_1,z_1...)
415 
416 .seealso: `DM`, `DMDA`, `DMSetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMDASetUniformCoordinates()`
417 @*/
418 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
419 {
420   PetscFunctionBegin;
421   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
422   PetscValidPointer(c, 2);
423   if (!dm->coordinates[0].x && dm->coordinates[0].xl) {
424     DM cdm = NULL;
425 
426     PetscCall(DMGetCoordinateDM(dm, &cdm));
427     PetscCall(DMCreateGlobalVector(cdm, &dm->coordinates[0].x));
428     PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[0].x, "coordinates"));
429     PetscCall(DMLocalToGlobalBegin(cdm, dm->coordinates[0].xl, INSERT_VALUES, dm->coordinates[0].x));
430     PetscCall(DMLocalToGlobalEnd(cdm, dm->coordinates[0].xl, INSERT_VALUES, dm->coordinates[0].x));
431   }
432   *c = dm->coordinates[0].x;
433   PetscFunctionReturn(0);
434 }
435 
436 /*@
437   DMSetCoordinates - Sets into the `DM` a global vector that holds the coordinates
438 
439   Collective on dm
440 
441   Input Parameters:
442 + dm - the `DM`
443 - c - coordinate vector
444 
445   Level: intermediate
446 
447   Notes:
448   The coordinates do not include those for ghost points, which are in the local vector.
449 
450   The vector c can be destroyed after the call
451 
452 .seealso: `DM`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMDASetUniformCoordinates()`
453 @*/
454 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
455 {
456   PetscFunctionBegin;
457   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
458   if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2);
459   PetscCall(PetscObjectReference((PetscObject)c));
460   PetscCall(VecDestroy(&dm->coordinates[0].x));
461   dm->coordinates[0].x = c;
462   PetscCall(VecDestroy(&dm->coordinates[0].xl));
463   PetscCall(DMCoarsenHookAdd(dm, DMRestrictHook_Coordinates, NULL, NULL));
464   PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_Coordinates, NULL, NULL));
465   PetscFunctionReturn(0);
466 }
467 
468 /*@
469   DMGetCellCoordinates - Gets a global vector with the cellwise coordinates associated with the `DM`.
470 
471   Collective on dm
472 
473   Input Parameter:
474 . dm - the `DM`
475 
476   Output Parameter:
477 . c - global coordinate vector
478 
479   Level: intermediate
480 
481   Notes:
482   This is a borrowed reference, so the user should NOT destroy this vector. When the `DM` is
483   destroyed the array will no longer be valid.
484 
485   Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).
486 
487 .seealso: `DM`, `DMGetCoordinates()`, `DMSetCellCoordinates()`, `DMGetCellCoordinatesLocal()`, `DMGetCellCoordinateDM()`
488 @*/
489 PetscErrorCode DMGetCellCoordinates(DM dm, Vec *c)
490 {
491   PetscFunctionBegin;
492   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
493   PetscValidPointer(c, 2);
494   if (!dm->coordinates[1].x && dm->coordinates[1].xl) {
495     DM cdm = NULL;
496 
497     PetscCall(DMGetCellCoordinateDM(dm, &cdm));
498     PetscCall(DMCreateGlobalVector(cdm, &dm->coordinates[1].x));
499     PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[1].x, "DG coordinates"));
500     PetscCall(DMLocalToGlobalBegin(cdm, dm->coordinates[1].xl, INSERT_VALUES, dm->coordinates[1].x));
501     PetscCall(DMLocalToGlobalEnd(cdm, dm->coordinates[1].xl, INSERT_VALUES, dm->coordinates[1].x));
502   }
503   *c = dm->coordinates[1].x;
504   PetscFunctionReturn(0);
505 }
506 
507 /*@
508   DMSetCellCoordinates - Sets into the `DM` a global vector that holds the cellwise coordinates
509 
510   Collective on dm
511 
512   Input Parameters:
513 + dm - the `DM`
514 - c - cellwise coordinate vector
515 
516   Level: intermediate
517 
518   Notes:
519   The coordinates do not include those for ghost points, which are in the local vector.
520 
521   The vector c should be destroyed by the caller.
522 
523 .seealso: `DM`, `DMGetCoordinates()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMGetCellCoordinatesLocal()`, `DMGetCellCoordinateDM()`
524 @*/
525 PetscErrorCode DMSetCellCoordinates(DM dm, Vec c)
526 {
527   PetscFunctionBegin;
528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
529   if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2);
530   PetscCall(PetscObjectReference((PetscObject)c));
531   PetscCall(VecDestroy(&dm->coordinates[1].x));
532   dm->coordinates[1].x = c;
533   PetscCall(VecDestroy(&dm->coordinates[1].xl));
534   PetscFunctionReturn(0);
535 }
536 
537 /*@
538   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that `DMGetCoordinatesLocalNoncollective()` can be used as non-collective afterwards.
539 
540   Collective on dm
541 
542   Input Parameter:
543 . dm - the `DM`
544 
545   Level: advanced
546 
547 .seealso: `DM`, `DMSetCoordinates()`, `DMGetCoordinatesLocalNoncollective()`
548 @*/
549 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
550 {
551   PetscFunctionBegin;
552   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
553   if (!dm->coordinates[0].xl && dm->coordinates[0].x) {
554     DM cdm = NULL;
555 
556     PetscCall(DMGetCoordinateDM(dm, &cdm));
557     PetscCall(DMCreateLocalVector(cdm, &dm->coordinates[0].xl));
558     PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[0].xl, "coordinates"));
559     PetscCall(DMGlobalToLocalBegin(cdm, dm->coordinates[0].x, INSERT_VALUES, dm->coordinates[0].xl));
560     PetscCall(DMGlobalToLocalEnd(cdm, dm->coordinates[0].x, INSERT_VALUES, dm->coordinates[0].xl));
561   }
562   PetscFunctionReturn(0);
563 }
564 
565 /*@
566   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the `DM`.
567 
568   Collective on dm the first time it is called
569 
570   Input Parameter:
571 . dm - the `DM`
572 
573   Output Parameter:
574 . c - coordinate vector
575 
576   Level: intermediate
577 
578   Notes:
579   This is a borrowed reference, so the user should NOT destroy this vector
580 
581   Each process has the local and ghost coordinates
582 
583   For `DMDA`, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
584   and (x_0,y_0,z_0,x_1,y_1,z_1...)
585 
586 .seealso: `DM`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()`, `DMGetCoordinatesLocalNoncollective()`
587 @*/
588 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
589 {
590   PetscFunctionBegin;
591   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
592   PetscValidPointer(c, 2);
593   PetscCall(DMGetCoordinatesLocalSetUp(dm));
594   *c = dm->coordinates[0].xl;
595   PetscFunctionReturn(0);
596 }
597 
598 /*@
599   DMGetCoordinatesLocalNoncollective - Non-collective version of `DMGetCoordinatesLocal()`. Fails if global coordinates have been set and `DMGetCoordinatesLocalSetUp()` not called.
600 
601   Not collective
602 
603   Input Parameter:
604 . dm - the `DM`
605 
606   Output Parameter:
607 . c - coordinate vector
608 
609   Level: advanced
610 
611   Note:
612   A previous call to  `DMGetCoordinatesLocal()` or `DMGetCoordinatesLocalSetUp()` ensures that a call to this function will not error.
613 
614 .seealso: `DM`, `DMGetCoordinatesLocalSetUp()`, `DMGetCoordinatesLocal()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()`
615 @*/
616 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
617 {
618   PetscFunctionBegin;
619   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
620   PetscValidPointer(c, 2);
621   PetscCheck(dm->coordinates[0].xl || !dm->coordinates[0].x, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
622   *c = dm->coordinates[0].xl;
623   PetscFunctionReturn(0);
624 }
625 
626 /*@
627   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and the section describing its layout.
628 
629   Not collective
630 
631   Input Parameters:
632 + dm - the `DM`
633 - p - the `IS` of points whose coordinates will be returned
634 
635   Output Parameters:
636 + pCoordSection - the `PetscSection` describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
637 - pCoord - the `Vec` with coordinates of points in p
638 
639   Level: advanced
640 
641   Notes:
642   `DMGetCoordinatesLocalSetUp()` must be called first. This function employs `DMGetCoordinatesLocalNoncollective()` so it is not collective.
643 
644   This creates a new vector, so the user SHOULD destroy this vector
645 
646   Each process has the local and ghost coordinates
647 
648   For `DMDA`, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
649   and (x_0,y_0,z_0,x_1,y_1,z_1...)
650 
651 .seealso: `DM`, `DMDA`, `DMSetCoordinatesLocal()`, `DMGetCoordinatesLocal()`, `DMGetCoordinatesLocalNoncollective()`, `DMGetCoordinatesLocalSetUp()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()`
652 @*/
653 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
654 {
655   DM                 cdm;
656   PetscSection       cs, newcs;
657   Vec                coords;
658   const PetscScalar *arr;
659   PetscScalar       *newarr = NULL;
660   PetscInt           n;
661 
662   PetscFunctionBegin;
663   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
664   PetscValidHeaderSpecific(p, IS_CLASSID, 2);
665   if (pCoordSection) PetscValidPointer(pCoordSection, 3);
666   if (pCoord) PetscValidPointer(pCoord, 4);
667   PetscCall(DMGetCoordinateDM(dm, &cdm));
668   PetscCall(DMGetLocalSection(cdm, &cs));
669   PetscCall(DMGetCoordinatesLocal(dm, &coords));
670   PetscCheck(coords, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
671   PetscCheck(cdm && cs, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
672   PetscCall(VecGetArrayRead(coords, &arr));
673   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void **)&newarr) : NULL));
674   PetscCall(VecRestoreArrayRead(coords, &arr));
675   if (pCoord) {
676     PetscCall(PetscSectionGetStorageSize(newcs, &n));
677     /* set array in two steps to mimic PETSC_OWN_POINTER */
678     PetscCall(VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord));
679     PetscCall(VecReplaceArray(*pCoord, newarr));
680   } else {
681     PetscCall(PetscFree(newarr));
682   }
683   if (pCoordSection) {
684     *pCoordSection = newcs;
685   } else PetscCall(PetscSectionDestroy(&newcs));
686   PetscFunctionReturn(0);
687 }
688 
689 /*@
690   DMSetCoordinatesLocal - Sets into the `DM` a local vector, including ghost points, that holds the coordinates
691 
692   Not collective
693 
694    Input Parameters:
695 +  dm - the `DM`
696 -  c - coordinate vector
697 
698   Level: intermediate
699 
700   Notes:
701   The coordinates of ghost points can be set using `DMSetCoordinates()`
702   followed by `DMGetCoordinatesLocal()`. This is intended to enable the
703   setting of ghost coordinates outside of the domain.
704 
705   The vector c should be destroyed by the caller.
706 
707 .seealso: `DM`, `DMGetCoordinatesLocal()`, `DMSetCoordinates()`, `DMGetCoordinates()`, `DMGetCoordinateDM()`
708 @*/
709 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
710 {
711   PetscFunctionBegin;
712   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
713   if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2);
714   PetscCall(PetscObjectReference((PetscObject)c));
715   PetscCall(VecDestroy(&dm->coordinates[0].xl));
716   dm->coordinates[0].xl = c;
717   PetscCall(VecDestroy(&dm->coordinates[0].x));
718   PetscFunctionReturn(0);
719 }
720 
721 /*@
722   DMGetCellCoordinatesLocalSetUp - Prepares a local vector of cellwise coordinates, so that `DMGetCellCoordinatesLocalNoncollective()` can be used as non-collective afterwards.
723 
724   Collective on dm
725 
726   Input Parameter:
727 . dm - the `DM`
728 
729   Level: advanced
730 
731 .seealso: `DM`, `DMGetCellCoordinatesLocalNoncollective()`
732 @*/
733 PetscErrorCode DMGetCellCoordinatesLocalSetUp(DM dm)
734 {
735   PetscFunctionBegin;
736   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
737   if (!dm->coordinates[1].xl && dm->coordinates[1].x) {
738     DM cdm = NULL;
739 
740     PetscCall(DMGetCellCoordinateDM(dm, &cdm));
741     PetscCall(DMCreateLocalVector(cdm, &dm->coordinates[1].xl));
742     PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[1].xl, "DG coordinates"));
743     PetscCall(DMGlobalToLocalBegin(cdm, dm->coordinates[1].x, INSERT_VALUES, dm->coordinates[1].xl));
744     PetscCall(DMGlobalToLocalEnd(cdm, dm->coordinates[1].x, INSERT_VALUES, dm->coordinates[1].xl));
745   }
746   PetscFunctionReturn(0);
747 }
748 
749 /*@
750   DMGetCellCoordinatesLocal - Gets a local vector with the cellwise coordinates associated with the `DM`.
751 
752   Collective on dm
753 
754   Input Parameter:
755 . dm - the `DM`
756 
757   Output Parameter:
758 . c - coordinate vector
759 
760   Level: intermediate
761 
762   Notes:
763   This is a borrowed reference, so the user should NOT destroy this vector
764 
765   Each process has the local and ghost coordinates
766 
767 .seealso: `DM`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMSetCellCoordinates()`, `DMGetCellCoordinateDM()`, `DMGetCellCoordinatesLocalNoncollective()`
768 @*/
769 PetscErrorCode DMGetCellCoordinatesLocal(DM dm, Vec *c)
770 {
771   PetscFunctionBegin;
772   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
773   PetscValidPointer(c, 2);
774   PetscCall(DMGetCellCoordinatesLocalSetUp(dm));
775   *c = dm->coordinates[1].xl;
776   PetscFunctionReturn(0);
777 }
778 
779 /*@
780   DMGetCellCoordinatesLocalNoncollective - Non-collective version of `DMGetCellCoordinatesLocal()`. Fails if global cellwise coordinates have been set and `DMGetCellCoordinatesLocalSetUp()` not called.
781 
782   Not collective
783 
784   Input Parameter:
785 . dm - the `DM`
786 
787   Output Parameter:
788 . c - cellwise coordinate vector
789 
790   Level: advanced
791 
792 .seealso: `DM`, `DMGetCellCoordinatesLocalSetUp()`, `DMGetCellCoordinatesLocal()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMSetCellCoordinates()`, `DMGetCellCoordinateDM()`
793 @*/
794 PetscErrorCode DMGetCellCoordinatesLocalNoncollective(DM dm, Vec *c)
795 {
796   PetscFunctionBegin;
797   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
798   PetscValidPointer(c, 2);
799   PetscCheck(dm->coordinates[1].xl || !dm->coordinates[1].x, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCellCoordinatesLocalSetUp() has not been called");
800   *c = dm->coordinates[1].xl;
801   PetscFunctionReturn(0);
802 }
803 
804 /*@
805   DMSetCellCoordinatesLocal - Sets into the `DM` a local vector including ghost points that holds the cellwise coordinates
806 
807   Not collective
808 
809    Input Parameters:
810 +  dm - the `DM`
811 -  c - cellwise coordinate vector
812 
813   Level: intermediate
814 
815   Notes:
816   The coordinates of ghost points can be set using `DMSetCoordinates()`
817   followed by `DMGetCoordinatesLocal()`. This is intended to enable the
818   setting of ghost coordinates outside of the domain.
819 
820   The vector c should be destroyed by the caller.
821 
822 .seealso: `DM`, `DMGetCellCoordinatesLocal()`, `DMSetCellCoordinates()`, `DMGetCellCoordinates()`, `DMGetCellCoordinateDM()`
823 @*/
824 PetscErrorCode DMSetCellCoordinatesLocal(DM dm, Vec c)
825 {
826   PetscFunctionBegin;
827   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
828   if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2);
829   PetscCall(PetscObjectReference((PetscObject)c));
830   PetscCall(VecDestroy(&dm->coordinates[1].xl));
831   dm->coordinates[1].xl = c;
832   PetscCall(VecDestroy(&dm->coordinates[1].x));
833   PetscFunctionReturn(0);
834 }
835 
836 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
837 {
838   PetscFunctionBegin;
839   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
840   PetscValidPointer(field, 2);
841   if (!dm->coordinates[0].field) {
842     if (dm->ops->createcoordinatefield) PetscCall((*dm->ops->createcoordinatefield)(dm, &dm->coordinates[0].field));
843   }
844   *field = dm->coordinates[0].field;
845   PetscFunctionReturn(0);
846 }
847 
848 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
849 {
850   PetscFunctionBegin;
851   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
852   if (field) PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 2);
853   PetscCall(PetscObjectReference((PetscObject)field));
854   PetscCall(DMFieldDestroy(&dm->coordinates[0].field));
855   dm->coordinates[0].field = field;
856   PetscFunctionReturn(0);
857 }
858 
859 /*@
860   DMGetLocalBoundingBox - Returns the bounding box for the piece of the `DM` on this process.
861 
862   Not collective
863 
864   Input Parameter:
865 . dm - the `DM`
866 
867   Output Parameters:
868 + lmin - local minimum coordinates (length coord dim, optional)
869 - lmax - local maximim coordinates (length coord dim, optional)
870 
871   Level: beginner
872 
873   Note:
874   If the `DM` is a `DMDA` and has no coordinates, the index bounds are returned instead.
875 
876 .seealso: `DM`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetBoundingBox()`
877 @*/
878 PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
879 {
880   Vec       coords = NULL;
881   PetscReal min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
882   PetscReal max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
883   PetscInt  cdim, i, j;
884 
885   PetscFunctionBegin;
886   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
887   PetscCall(DMGetCoordinateDim(dm, &cdim));
888   PetscCall(DMGetCoordinatesLocal(dm, &coords));
889   if (coords) {
890     const PetscScalar *local_coords;
891     PetscInt           N, Ni;
892 
893     for (j = cdim; j < 3; ++j) {
894       min[j] = 0;
895       max[j] = 0;
896     }
897     PetscCall(VecGetArrayRead(coords, &local_coords));
898     PetscCall(VecGetLocalSize(coords, &N));
899     Ni = N / cdim;
900     for (i = 0; i < Ni; ++i) {
901       for (j = 0; j < cdim; ++j) {
902         min[j] = PetscMin(min[j], PetscRealPart(local_coords[i * cdim + j]));
903         max[j] = PetscMax(max[j], PetscRealPart(local_coords[i * cdim + j]));
904       }
905     }
906     PetscCall(VecRestoreArrayRead(coords, &local_coords));
907     PetscCall(DMGetCellCoordinatesLocal(dm, &coords));
908     if (coords) {
909       PetscCall(VecGetArrayRead(coords, &local_coords));
910       PetscCall(VecGetLocalSize(coords, &N));
911       Ni = N / cdim;
912       for (i = 0; i < Ni; ++i) {
913         for (j = 0; j < cdim; ++j) {
914           min[j] = PetscMin(min[j], PetscRealPart(local_coords[i * cdim + j]));
915           max[j] = PetscMax(max[j], PetscRealPart(local_coords[i * cdim + j]));
916         }
917       }
918       PetscCall(VecRestoreArrayRead(coords, &local_coords));
919     }
920   } else {
921     PetscBool isda;
922 
923     PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &isda));
924     if (isda) PetscCall(DMGetLocalBoundingIndices_DMDA(dm, min, max));
925   }
926   if (lmin) PetscCall(PetscArraycpy(lmin, min, cdim));
927   if (lmax) PetscCall(PetscArraycpy(lmax, max, cdim));
928   PetscFunctionReturn(0);
929 }
930 
931 /*@
932   DMGetBoundingBox - Returns the global bounding box for the `DM`.
933 
934   Collective
935 
936   Input Parameter:
937 . dm - the `DM`
938 
939   Output Parameters:
940 + gmin - global minimum coordinates (length coord dim, optional)
941 - gmax - global maximim coordinates (length coord dim, optional)
942 
943   Level: beginner
944 
945 .seealso: `DM`, `DMGetLocalBoundingBox()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`
946 @*/
947 PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
948 {
949   PetscReal   lmin[3], lmax[3];
950   PetscInt    cdim;
951   PetscMPIInt count;
952 
953   PetscFunctionBegin;
954   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
955   PetscCall(DMGetCoordinateDim(dm, &cdim));
956   PetscCall(PetscMPIIntCast(cdim, &count));
957   PetscCall(DMGetLocalBoundingBox(dm, lmin, lmax));
958   if (gmin) PetscCall(MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm)));
959   if (gmax) PetscCall(MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm)));
960   PetscFunctionReturn(0);
961 }
962 
963 /*@
964   DMProjectCoordinates - Project coordinates to a different space
965 
966   Input Parameters:
967 + dm      - The `DM` object
968 - disc    - The new coordinate discretization or NULL to ensure a coordinate discretization exists
969 
970   Level: intermediate
971 
972   Notes:
973   A `PetscFE` defines an approximation space using a `PetscSpace`, which represents the basis functions, and a `PetscDualSpace`, which defines the interpolation operation
974   in the space.
975 
976   This function takes the current mesh coordinates, which are discretized using some `PetscFE` space, and projects this function into a new `PetscFE` space.
977   The coordinate projection is done on the continuous coordinates, and if possible, the discontinuous coordinates are also updated.
978 
979   Developer Note:
980   With more effort, we could directly project the discontinuous coordinates also.
981 
982 .seealso: `DM`, `PetscFE`, `DMGetCoordinateField()`
983 @*/
984 PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
985 {
986   PetscFE      discOld;
987   PetscClassId classid;
988   DM           cdmOld, cdmNew;
989   Vec          coordsOld, coordsNew;
990   Mat          matInterp;
991   PetscBool    same_space = PETSC_TRUE;
992 
993   PetscFunctionBegin;
994   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
995   if (disc) PetscValidHeaderSpecific(disc, PETSCFE_CLASSID, 2);
996 
997   PetscCall(DMGetCoordinateDM(dm, &cdmOld));
998   /* Check current discretization is compatible */
999   PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject *)&discOld));
1000   PetscCall(PetscObjectGetClassId((PetscObject)discOld, &classid));
1001   if (classid != PETSCFE_CLASSID) {
1002     if (classid == PETSC_CONTAINER_CLASSID) {
1003       PetscFE        feLinear;
1004       DMPolytopeType ct;
1005       PetscInt       dim, dE, cStart, cEnd;
1006       PetscBool      simplex;
1007 
1008       /* Assume linear vertex coordinates */
1009       PetscCall(DMGetDimension(dm, &dim));
1010       PetscCall(DMGetCoordinateDim(dm, &dE));
1011       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1012       if (cEnd > cStart) {
1013         PetscCall(DMPlexGetCellType(dm, cStart, &ct));
1014         switch (ct) {
1015         case DM_POLYTOPE_TRI_PRISM:
1016         case DM_POLYTOPE_TRI_PRISM_TENSOR:
1017           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
1018         default:
1019           break;
1020         }
1021       }
1022       PetscCall(DMPlexIsSimplex(dm, &simplex));
1023       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear));
1024       PetscCall(DMSetField(cdmOld, 0, NULL, (PetscObject)feLinear));
1025       PetscCall(PetscFEDestroy(&feLinear));
1026       PetscCall(DMCreateDS(cdmOld));
1027       PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject *)&discOld));
1028     } else {
1029       const char *discname;
1030 
1031       PetscCall(PetscObjectGetType((PetscObject)discOld, &discname));
1032       SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
1033     }
1034   }
1035   if (!disc) PetscFunctionReturn(0);
1036   { // Check if the new space is the same as the old modulo quadrature
1037     PetscDualSpace dsOld, ds;
1038     PetscCall(PetscFEGetDualSpace(discOld, &dsOld));
1039     PetscCall(PetscFEGetDualSpace(disc, &ds));
1040     PetscCall(PetscDualSpaceEqual(dsOld, ds, &same_space));
1041   }
1042   /* Make a fresh clone of the coordinate DM */
1043   PetscCall(DMClone(cdmOld, &cdmNew));
1044   PetscCall(DMSetField(cdmNew, 0, NULL, (PetscObject)disc));
1045   PetscCall(DMCreateDS(cdmNew));
1046   PetscCall(DMGetCoordinates(dm, &coordsOld));
1047   if (same_space) {
1048     PetscCall(PetscObjectReference((PetscObject)coordsOld));
1049     coordsNew = coordsOld;
1050   } else { // Project the coordinate vector from old to new space
1051     PetscCall(DMCreateGlobalVector(cdmNew, &coordsNew));
1052     PetscCall(DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL));
1053     PetscCall(MatInterpolate(matInterp, coordsOld, coordsNew));
1054     PetscCall(MatDestroy(&matInterp));
1055   }
1056   /* Set new coordinate structures */
1057   PetscCall(DMSetCoordinateField(dm, NULL));
1058   PetscCall(DMSetCoordinateDM(dm, cdmNew));
1059   PetscCall(DMSetCoordinates(dm, coordsNew));
1060   PetscCall(VecDestroy(&coordsNew));
1061   PetscCall(DMDestroy(&cdmNew));
1062   PetscFunctionReturn(0);
1063 }
1064 
1065 /*@
1066   DMLocatePoints - Locate the points in v in the mesh and return a `PetscSF` of the containing cells
1067 
1068   Collective on v (see explanation below)
1069 
1070   Input Parameters:
1071 + dm - The `DM`
1072 - ltype - The type of point location, e.g. `DM_POINTLOCATION_NONE` or `DM_POINTLOCATION_NEAREST`
1073 
1074   Input/Output Parameters:
1075 + v - The `Vec` of points, on output contains the nearest mesh points to the given points if `DM_POINTLOCATION_NEAREST` is used
1076 - cellSF - Points to either NULL, or a `PetscSF` with guesses for which cells contain each point;
1077            on output, the `PetscSF` containing the ranks and local indices of the containing points
1078 
1079   Level: developer
1080 
1081   Notes:
1082   To do a search of the local cells of the mesh, v should have `PETSC_COMM_SELF` as its communicator.
1083   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
1084 
1085   Points will only be located in owned cells, not overlap cells arising from `DMPlexDistribute()` or other overlapping distributions.
1086 
1087   If *cellSF is NULL on input, a `PetscSF` will be created.
1088   If *cellSF is not NULL on input, it should point to an existing `PetscSF`, whose graph will be used as initial guesses.
1089 
1090   An array that maps each point to its containing cell can be obtained with
1091 .vb
1092     const PetscSFNode *cells;
1093     PetscInt           nFound;
1094     const PetscInt    *found;
1095 
1096     PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
1097 .ve
1098 
1099   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
1100   the index of the cell in its rank's local numbering.
1101 
1102 .seealso: `DM`, `DMSetCoordinates()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMPointLocationType`
1103 @*/
1104 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
1105 {
1106   PetscFunctionBegin;
1107   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1108   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
1109   PetscValidPointer(cellSF, 4);
1110   if (*cellSF) {
1111     PetscMPIInt result;
1112 
1113     PetscValidHeaderSpecific(*cellSF, PETSCSF_CLASSID, 4);
1114     PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)v), PetscObjectComm((PetscObject)*cellSF), &result));
1115     PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "cellSF must have a communicator congruent to v's");
1116   } else {
1117     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)v), cellSF));
1118   }
1119   PetscCall(PetscLogEventBegin(DM_LocatePoints, dm, 0, 0, 0));
1120   PetscUseTypeMethod(dm, locatepoints, v, ltype, *cellSF);
1121   PetscCall(PetscLogEventEnd(DM_LocatePoints, dm, 0, 0, 0));
1122   PetscFunctionReturn(0);
1123 }
1124