xref: /petsc/src/vec/is/sf/utils/sfcoord.c (revision cc6b3d485b7186cdb6e8e6b8ee2dca644baa10ec)
18b5d2d36SJed Brown #include <petsc/private/sfimpl.h> /*I  "petscsf.h"   I*/
28b5d2d36SJed Brown 
GetBoundingBox_Internal(PetscInt npoints,PetscInt dim,const PetscReal * coords,PetscReal * bbox)38b5d2d36SJed Brown static PetscErrorCode GetBoundingBox_Internal(PetscInt npoints, PetscInt dim, const PetscReal *coords, PetscReal *bbox)
48b5d2d36SJed Brown {
58b5d2d36SJed Brown   PetscFunctionBegin;
68b5d2d36SJed Brown   for (PetscInt d = 0; d < dim; d++) {
78b5d2d36SJed Brown     bbox[0 * dim + d] = PETSC_MAX_REAL;
88b5d2d36SJed Brown     bbox[1 * dim + d] = PETSC_MIN_REAL;
98b5d2d36SJed Brown   }
108b5d2d36SJed Brown   for (PetscInt i = 0; i < npoints; i++) {
118b5d2d36SJed Brown     for (PetscInt d = 0; d < dim; d++) {
128b5d2d36SJed Brown       bbox[0 * dim + d] = PetscMin(bbox[0 * dim + d], coords[i * dim + d]);
138b5d2d36SJed Brown       bbox[1 * dim + d] = PetscMax(bbox[1 * dim + d], coords[i * dim + d]);
148b5d2d36SJed Brown     }
158b5d2d36SJed Brown   }
163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
178b5d2d36SJed Brown }
188b5d2d36SJed Brown 
IntersectBoundingBox_Internal(PetscInt dim,const PetscReal * a,const PetscReal * b,PetscReal tol)198b5d2d36SJed Brown static PetscBool IntersectBoundingBox_Internal(PetscInt dim, const PetscReal *a, const PetscReal *b, PetscReal tol)
208b5d2d36SJed Brown {
218b5d2d36SJed Brown   for (PetscInt d = 0; d < dim; d++) {
228b5d2d36SJed Brown     if (a[1 * dim + d] + tol < b[0 * dim + d] || b[1 * dim + d] + tol < a[0 * dim + d]) return PETSC_FALSE;
238b5d2d36SJed Brown   }
248b5d2d36SJed Brown   return PETSC_TRUE;
258b5d2d36SJed Brown }
268b5d2d36SJed Brown 
InBoundingBox_Internal(PetscInt dim,const PetscReal * x,const PetscReal * bbox,PetscReal tol)278b5d2d36SJed Brown static PetscBool InBoundingBox_Internal(PetscInt dim, const PetscReal *x, const PetscReal *bbox, PetscReal tol)
288b5d2d36SJed Brown {
298b5d2d36SJed Brown   for (PetscInt d = 0; d < dim; d++) {
308b5d2d36SJed Brown     if (x[d] + tol < bbox[0 * dim + d] || bbox[1 * dim + d] + tol < x[d]) return PETSC_FALSE;
318b5d2d36SJed Brown   }
328b5d2d36SJed Brown   return PETSC_TRUE;
338b5d2d36SJed Brown }
348b5d2d36SJed Brown 
358b5d2d36SJed Brown /*@
368b5d2d36SJed Brown   PetscSFSetGraphFromCoordinates - Create SF by fuzzy matching leaf coordinates to root coordinates
378b5d2d36SJed Brown 
388b5d2d36SJed Brown   Collective
398b5d2d36SJed Brown 
408b5d2d36SJed Brown   Input Parameters:
418b5d2d36SJed Brown + sf         - PetscSF to set graph on
428b5d2d36SJed Brown . nroots     - number of root coordinates
438b5d2d36SJed Brown . nleaves    - number of leaf coordinates
448b5d2d36SJed Brown . dim        - spatial dimension of coordinates
458b5d2d36SJed Brown . tol        - positive tolerance for matching
468b5d2d36SJed Brown . rootcoords - array of root coordinates in which root i component d is [i*dim+d]
478b5d2d36SJed Brown - leafcoords - array of root coordinates in which leaf i component d is [i*dim+d]
488b5d2d36SJed Brown 
498b5d2d36SJed Brown   Notes:
508b5d2d36SJed Brown   The tolerance typically represents the rounding error incurred by numerically computing coordinates via
518b5d2d36SJed Brown   possibly-different procedures. Passing anything from `PETSC_SMALL` to `100 * PETSC_MACHINE_EPSILON` is appropriate for
528b5d2d36SJed Brown   most use cases.
538b5d2d36SJed Brown 
548b5d2d36SJed Brown   Example:
558b5d2d36SJed Brown   As a motivating example, consider fluid flow in the x direction with y (distance from a wall). The spanwise direction,
568b5d2d36SJed Brown   z, has periodic boundary conditions and needs some spanwise length to allow turbulent structures to develop. The
578b5d2d36SJed Brown   distribution is stationary with respect to z, so you want to average turbulence variables (like Reynolds stress) over
588b5d2d36SJed Brown   the z direction. It is complicated in a 3D simulation with arbitrary partitioner to uniquely number the nodes or
598b5d2d36SJed Brown   quadrature point coordinates to average these quantities into a 2D plane where they will be visualized, but it's easy
608b5d2d36SJed Brown   to compute the projection of each 3D point into the 2D plane.
618b5d2d36SJed Brown 
628b5d2d36SJed Brown   Suppose a 2D target mesh and 3D source mesh (logically an extrusion of the 2D, though perhaps not created in that way)
638b5d2d36SJed Brown   are distributed independently on a communicator. Each rank passes its 2D target points as root coordinates and the 2D
648b5d2d36SJed Brown   projection of its 3D source points as leaf coordinates. Calling `PetscSFReduceBegin()`/`PetscSFReduceEnd()` on the
658b5d2d36SJed Brown   result will sum data from the 3D sources to the 2D targets.
668b5d2d36SJed Brown 
678b5d2d36SJed Brown   As a concrete example, consider three MPI ranks with targets (roots)
688b5d2d36SJed Brown .vb
698b5d2d36SJed Brown Rank 0: (0, 0), (0, 1)
708b5d2d36SJed Brown Rank 1: (0.1, 0), (0.1, 1)
718b5d2d36SJed Brown Rank 2: (0.2, 0), (0.2, 1)
728b5d2d36SJed Brown .ve
738b5d2d36SJed Brown   Note that targets must be uniquely owned. Suppose also that we identify the following leaf coordinates (perhaps via projection from a 3D space).
748b5d2d36SJed Brown .vb
758b5d2d36SJed Brown Rank 0: (0, 0), (0.1, 0), (0, 1), (0.1, 1)
768b5d2d36SJed Brown Rank 1: (0, 0), (0.1, 0), (0.2, 0), (0, 1), (0.1, 1)
778b5d2d36SJed Brown Rank 2: (0.1, 0), (0.2, 0), (0.1, 1), (0.2, 1)
788b5d2d36SJed Brown .ve
798b5d2d36SJed Brown   Leaf coordinates may be repeated, both on a rank and between ranks. This example yields the following `PetscSF` capable of reducing from sources to targets.
808b5d2d36SJed Brown .vb
818b5d2d36SJed Brown Roots by rank
828b5d2d36SJed Brown [0]  0:   0.0000e+00   0.0000e+00   0.0000e+00   1.0000e+00
838b5d2d36SJed Brown [1]  0:   1.0000e-01   0.0000e+00   1.0000e-01   1.0000e+00
848b5d2d36SJed Brown [2]  0:   2.0000e-01   0.0000e+00   2.0000e-01   1.0000e+00
858b5d2d36SJed Brown Leaves by rank
868b5d2d36SJed Brown [0]  0:   0.0000e+00   0.0000e+00   1.0000e-01   0.0000e+00   0.0000e+00
878b5d2d36SJed Brown [0]  5:   1.0000e+00   1.0000e-01   1.0000e+00
888b5d2d36SJed Brown [1]  0:   0.0000e+00   0.0000e+00   1.0000e-01   0.0000e+00   2.0000e-01
898b5d2d36SJed Brown [1]  5:   0.0000e+00   0.0000e+00   1.0000e+00   1.0000e-01   1.0000e+00
908b5d2d36SJed Brown [1] 10:   2.0000e-01   1.0000e+00
918b5d2d36SJed Brown [2]  0:   1.0000e-01   0.0000e+00   2.0000e-01   0.0000e+00   1.0000e-01
928b5d2d36SJed Brown [2]  5:   1.0000e+00   2.0000e-01   1.0000e+00
938b5d2d36SJed Brown PetscSF Object: 3 MPI processes
948b5d2d36SJed Brown   type: basic
958b5d2d36SJed Brown   [0] Number of roots=2, leaves=4, remote ranks=2
968b5d2d36SJed Brown   [0] 0 <- (0,0)
978b5d2d36SJed Brown   [0] 1 <- (1,0)
988b5d2d36SJed Brown   [0] 2 <- (0,1)
998b5d2d36SJed Brown   [0] 3 <- (1,1)
1008b5d2d36SJed Brown   [1] Number of roots=2, leaves=6, remote ranks=3
1018b5d2d36SJed Brown   [1] 0 <- (0,0)
1028b5d2d36SJed Brown   [1] 1 <- (1,0)
1038b5d2d36SJed Brown   [1] 2 <- (2,0)
1048b5d2d36SJed Brown   [1] 3 <- (0,1)
1058b5d2d36SJed Brown   [1] 4 <- (1,1)
1068b5d2d36SJed Brown   [1] 5 <- (2,1)
1078b5d2d36SJed Brown   [2] Number of roots=2, leaves=4, remote ranks=2
1088b5d2d36SJed Brown   [2] 0 <- (1,0)
1098b5d2d36SJed Brown   [2] 1 <- (2,0)
1108b5d2d36SJed Brown   [2] 2 <- (1,1)
1118b5d2d36SJed Brown   [2] 3 <- (2,1)
1128b5d2d36SJed Brown .ve
1138b5d2d36SJed Brown 
1148b5d2d36SJed Brown   Level: advanced
1158b5d2d36SJed Brown 
1168b5d2d36SJed Brown .seealso: `PetscSFCreate()`, `PetscSFSetGraph()`, `PetscSFCreateByMatchingIndices()`
1178b5d2d36SJed Brown @*/
PetscSFSetGraphFromCoordinates(PetscSF sf,PetscInt nroots,PetscInt nleaves,PetscInt dim,PetscReal tol,const PetscReal rootcoords[],const PetscReal leafcoords[])118cf84bf9eSBarry Smith PetscErrorCode PetscSFSetGraphFromCoordinates(PetscSF sf, PetscInt nroots, PetscInt nleaves, PetscInt dim, PetscReal tol, const PetscReal rootcoords[], const PetscReal leafcoords[])
1198b5d2d36SJed Brown {
1208b5d2d36SJed Brown   PetscReal    bbox[6], *bboxes, *target_coords;
121835f2295SStefano Zampini   PetscMPIInt  size, *ranks_needed, num_ranks, msize;
1228b5d2d36SJed Brown   PetscInt    *root_sizes, *root_starts;
1238b5d2d36SJed Brown   PetscSFNode *premote, *lremote;
1248b5d2d36SJed Brown   PetscSF      psf;
1258b5d2d36SJed Brown   MPI_Datatype unit;
1268b5d2d36SJed Brown   MPI_Comm     comm;
1278b5d2d36SJed Brown 
1288b5d2d36SJed Brown   PetscFunctionBegin;
129*9b6401adSJames Wright   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
130*9b6401adSJames Wright   PetscValidLogicalCollectiveInt(sf, dim, 4);
131*9b6401adSJames Wright   PetscValidLogicalCollectiveReal(sf, tol, 5);
132*9b6401adSJames Wright   if (nroots != 0) PetscAssertPointer(rootcoords, 6);
133*9b6401adSJames Wright   if (nleaves != 0) PetscAssertPointer(leafcoords, 7);
1348b5d2d36SJed Brown   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1358b5d2d36SJed Brown   PetscCall(GetBoundingBox_Internal(nroots, dim, rootcoords, bbox));
1368b5d2d36SJed Brown   PetscCallMPI(MPI_Comm_size(comm, &size));
1378b5d2d36SJed Brown   PetscCall(PetscMalloc1(size * 2 * dim, &bboxes));
138835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(2 * dim, &msize));
139835f2295SStefano Zampini   PetscCallMPI(MPI_Allgather(bbox, msize, MPIU_REAL, bboxes, msize, MPIU_REAL, comm));
1408b5d2d36SJed Brown   PetscCall(GetBoundingBox_Internal(nleaves, dim, leafcoords, bbox));
1418b5d2d36SJed Brown   PetscCall(PetscMalloc1(size, &root_sizes));
1428b5d2d36SJed Brown   PetscCallMPI(MPI_Allgather(&nroots, 1, MPIU_INT, root_sizes, 1, MPIU_INT, comm));
1438b5d2d36SJed Brown 
1448b5d2d36SJed Brown   PetscCall(PetscMalloc2(size, &ranks_needed, size + 1, &root_starts));
1458b5d2d36SJed Brown   root_starts[0] = 0;
1468b5d2d36SJed Brown   num_ranks      = 0;
1478b5d2d36SJed Brown   for (PetscMPIInt r = 0; r < size; r++) {
1488b5d2d36SJed Brown     if (IntersectBoundingBox_Internal(dim, bbox, &bboxes[2 * dim * r], tol)) {
1498b5d2d36SJed Brown       ranks_needed[num_ranks++] = r;
1508b5d2d36SJed Brown       root_starts[num_ranks]    = root_starts[num_ranks - 1] + root_sizes[r];
1518b5d2d36SJed Brown     }
1528b5d2d36SJed Brown   }
1538b5d2d36SJed Brown   PetscCall(PetscFree(root_sizes));
1548b5d2d36SJed Brown   PetscCall(PetscMalloc1(root_starts[num_ranks], &premote));
1558b5d2d36SJed Brown   for (PetscInt i = 0; i < num_ranks; i++) {
1568b5d2d36SJed Brown     for (PetscInt j = root_starts[i]; j < root_starts[i + 1]; j++) {
1578b5d2d36SJed Brown       premote[j].rank  = ranks_needed[i];
1588b5d2d36SJed Brown       premote[j].index = j - root_starts[i];
1598b5d2d36SJed Brown     }
1608b5d2d36SJed Brown   }
1618b5d2d36SJed Brown   PetscCall(PetscSFCreate(comm, &psf));
1628b5d2d36SJed Brown   PetscCall(PetscSFSetGraph(psf, nroots, root_starts[num_ranks], NULL, PETSC_USE_POINTER, premote, PETSC_USE_POINTER));
1638b5d2d36SJed Brown   PetscCall(PetscMalloc1(root_starts[num_ranks] * dim, &target_coords));
164835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(dim, &msize));
165835f2295SStefano Zampini   PetscCallMPI(MPI_Type_contiguous(msize, MPIU_REAL, &unit));
1668b5d2d36SJed Brown   PetscCallMPI(MPI_Type_commit(&unit));
1678b5d2d36SJed Brown   PetscCall(PetscSFBcastBegin(psf, unit, rootcoords, target_coords, MPI_REPLACE));
1688b5d2d36SJed Brown   PetscCall(PetscSFBcastEnd(psf, unit, rootcoords, target_coords, MPI_REPLACE));
1698b5d2d36SJed Brown   PetscCallMPI(MPI_Type_free(&unit));
1708b5d2d36SJed Brown   PetscCall(PetscSFDestroy(&psf));
1718b5d2d36SJed Brown 
1728b5d2d36SJed Brown   // Condense targets to only those that lie within our bounding box
1738b5d2d36SJed Brown   PetscInt num_targets = 0;
1748b5d2d36SJed Brown   for (PetscInt i = 0; i < root_starts[num_ranks]; i++) {
1758b5d2d36SJed Brown     if (InBoundingBox_Internal(dim, &target_coords[i * dim], bbox, tol)) {
1768b5d2d36SJed Brown       premote[num_targets] = premote[i];
1778b5d2d36SJed Brown       for (PetscInt d = 0; d < dim; d++) target_coords[num_targets * dim + d] = target_coords[i * dim + d];
1788b5d2d36SJed Brown       num_targets++;
1798b5d2d36SJed Brown     }
1808b5d2d36SJed Brown   }
1818b5d2d36SJed Brown   PetscCall(PetscFree(bboxes));
1828b5d2d36SJed Brown   PetscCall(PetscFree2(ranks_needed, root_starts));
1838b5d2d36SJed Brown 
1848b5d2d36SJed Brown   PetscCall(PetscMalloc1(nleaves, &lremote));
185c0713208SJames Wright   PetscKDTree tree;
186c0713208SJames Wright   PetscCount *indices;
187c0713208SJames Wright   PetscReal  *distances;
188c0713208SJames Wright 
189c0713208SJames Wright   PetscCall(PetscKDTreeCreate(num_targets, dim, target_coords, PETSC_USE_POINTER, PETSC_DETERMINE, &tree));
190c0713208SJames Wright   PetscCall(PetscMalloc2(nleaves, &indices, nleaves, &distances));
191c0713208SJames Wright   PetscCall(PetscKDTreeQueryPointsNearestNeighbor(tree, nleaves, leafcoords, tol, indices, distances));
1928b5d2d36SJed Brown   for (PetscInt i = 0; i < nleaves; i++) {
193c0713208SJames Wright     if (distances[i] < tol) {
194c0713208SJames Wright       lremote[i] = premote[indices[i]];
195c0713208SJames Wright     } else {
1968b5d2d36SJed Brown       switch (dim) {
1978b5d2d36SJed Brown       case 1:
1988b5d2d36SJed Brown         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "No target found for leaf coordinate %g", (double)leafcoords[i * dim + 0]);
1998b5d2d36SJed Brown       case 2:
2008b5d2d36SJed Brown         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "No target found for leaf coordinate (%g, %g)", (double)leafcoords[i * dim + 0], (double)leafcoords[i * dim + 1]);
2018b5d2d36SJed Brown       case 3:
2028b5d2d36SJed Brown         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "No target found for leaf coordinate (%g, %g, %g)", (double)leafcoords[i * dim + 0], (double)leafcoords[i * dim + 1], (double)leafcoords[i * dim + 2]);
2038b5d2d36SJed Brown       }
2048b5d2d36SJed Brown     }
205c0713208SJames Wright   }
206c0713208SJames Wright   PetscCall(PetscFree2(indices, distances));
207c0713208SJames Wright   PetscCall(PetscKDTreeDestroy(&tree));
2088b5d2d36SJed Brown   PetscCall(PetscFree(premote));
2098b5d2d36SJed Brown   PetscCall(PetscFree(target_coords));
2108b5d2d36SJed Brown   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, NULL, PETSC_USE_POINTER, lremote, PETSC_OWN_POINTER));
2113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2128b5d2d36SJed Brown }
213