730 const Kokkos::View<Real*, peclet::core::MemSpace>& posFlat,
731 const Kokkos::View<Real*, peclet::core::MemSpace>& weight,
int N,
const Real L[3],
733 Kokkos::View<long*, peclet::core::MemSpace> gid = {}, Sdf sdf = {},
bool withForceGeom =
true,
734 int nBuild = -1, Kokkos::View<int*, peclet::core::MemSpace> outNp = {},
735 Kokkos::View<int*, peclet::core::MemSpace> outNt = {},
736 Kokkos::View<int*, peclet::core::MemSpace> outPnbr = {},
737 Kokkos::View<unsigned*, peclet::core::MemSpace> outTri = {},
738 Kokkos::View<int*, peclet::core::MemSpace> outCand = {},
739 Kokkos::View<int*, peclet::core::MemSpace> outCandCnt = {},
int candCap = 0,
740 WorklistCache<Real>* wlc =
nullptr, WallStore<Real> outWall = {},
bool withAreaGrad =
false,
741 Kokkos::View<int*, peclet::core::MemSpace> outNear = {},
742 Kokkos::View<int*, peclet::core::MemSpace> outNearCnt = {},
int nearCap = 0,
743 Real nearMargin = Real(0),
bool withWallFD =
false,
bool withMoments =
false,
744 bool profile =
false) {
745 using peclet::core::MemSpace;
746 using Exec = peclet::core::ExecSpace;
750 const bool emitTopo = outNp.extent(0) ==
static_cast<size_t>(N);
751 const bool emitCand = outCand.extent(0) > 0 && candCap > 0;
756 const bool haveGid = gid.extent(0) ==
static_cast<size_t>(N);
758 const int nBuildEff = (nBuild >= 0 && nBuild < N) ? nBuild : N;
762 const bool prof = profile;
763 Kokkos::Timer ptimer;
764 double tGrid = 0, tBuild = 0, tCsr = 0;
769 auto grid = buildTessGrid<Real, Weighted>(posFlat, weight, N, L, sw, densityCount, gid, wlc);
774 const Real Lx = grid.Lx, Ly = grid.Ly, Lz = grid.Lz;
775 const Real icx = grid.icx, icy = grid.icy, icz = grid.icz, minCsz = grid.minCsz;
776 const int dimx = grid.dimx, dimy = grid.dimy, dimz = grid.dimz;
777 const int nOff = grid.nOff, wlS = grid.wlS;
778 const bool useMorton = grid.useMorton;
782 tGrid = ptimer.seconds();
788 Kokkos::View<Real*, MemSpace> cellVol(
"cellVol", N);
789 Kokkos::View<int*, MemSpace> facetCount(
"facetCount", N);
790 Kokkos::View<int*, MemSpace> status(
"status", N);
791 Kokkos::View<int*, MemSpace> cellFacetBase(
"cellFacetBase", N);
812 constexpr size_t kMeanFacets = 18;
813 size_t facetCap = (size_t)N * kMeanFacets;
814 using Kokkos::view_alloc;
815 using Kokkos::WithoutInitializing;
816 Kokkos::View<int*, MemSpace> oNbr;
817 Kokkos::View<Real*, MemSpace> oArea, oDV, oConn;
818 Kokkos::View<int*, MemSpace> facetCursor(
"facetCursor", 1);
822 size_t edgeCap = withAreaGrad ? facetCap * 8 : 0;
823 Kokkos::View<int*, MemSpace> oEdgeOff, oEdgeCnt, oEdgeFacet, edgeCursor;
824 Kokkos::View<Real*, MemSpace> oEdgeGrad, oEdgeLen;
826 edgeCursor = Kokkos::View<int*, MemSpace>(
"edgeCursor", 1);
828 Kokkos::View<Real*, MemSpace> oMoment2;
830 auto allocOverBuffers = [&]() {
831 oNbr = Kokkos::View<int*, MemSpace>(view_alloc(std::string(
"oNbr"), WithoutInitializing),
833 oArea = Kokkos::View<Real*, MemSpace>(view_alloc(std::string(
"oArea"), WithoutInitializing),
835 oDV = Kokkos::View<Real*, MemSpace>(view_alloc(std::string(
"oDV"), WithoutInitializing),
837 oConn = Kokkos::View<Real*, MemSpace>(view_alloc(std::string(
"oConn"), WithoutInitializing),
839 Kokkos::deep_copy(facetCursor, 0);
841 oEdgeOff = Kokkos::View<int*, MemSpace>(
842 view_alloc(std::string(
"oEdgeOff"), WithoutInitializing), facetCap);
843 oEdgeCnt = Kokkos::View<int*, MemSpace>(
844 view_alloc(std::string(
"oEdgeCnt"), WithoutInitializing), facetCap);
845 oEdgeFacet = Kokkos::View<int*, MemSpace>(
846 view_alloc(std::string(
"oEdgeFacet"), WithoutInitializing), edgeCap);
847 oEdgeGrad = Kokkos::View<Real*, MemSpace>(
848 view_alloc(std::string(
"oEdgeGrad"), WithoutInitializing), edgeCap * 3);
849 oEdgeLen = Kokkos::View<Real*, MemSpace>(
850 view_alloc(std::string(
"oEdgeLen"), WithoutInitializing), edgeCap * 4);
851 Kokkos::deep_copy(edgeCursor, 0);
854 oMoment2 = Kokkos::View<Real*, MemSpace>(
855 view_alloc(std::string(
"oMoment2"), WithoutInitializing), facetCap);
859 Kokkos::View<Real*, MemSpace> oWallDV, oWallDA;
860 if (withWallFD && !std::is_same_v<Sdf, NoSdf>) {
861 oWallDV = Kokkos::View<Real*, MemSpace>(
"cellWallDV", (
size_t)N * 3);
862 oWallDA = Kokkos::View<Real*, MemSpace>(
"cellWallDA", (
size_t)N * 3);
865 std::fprintf(stderr,
"[worklist] sw=%d nOff=%d\n", sw, nOff);
870 Kokkos::View<unsigned char*, MemSpace>
874 Real wMaxAll = Real(0);
875 if constexpr (Weighted) {
876 if (weight.extent(0) ==
static_cast<size_t>(N)) {
877 Kokkos::parallel_reduce(
878 "wmax", Kokkos::RangePolicy<Exec>(0, N),
879 KOKKOS_LAMBDA(
int idx, Real& m) { m = weight(idx) > m ? weight(idx) : m; },
880 Kokkos::Max<Real>(wMaxAll));
884 CellBuilder<Real, Weighted, Sdf, false, MAXP, MAXT> op{grid.binned,
945 const int nBuildL = nBuildEff;
946 auto binnedV0 = grid.binned;
947 int nFacetsRaw = 0, nEdgesRaw = 0;
948 int overBufferRebuilds = 0;
949 for (
int attempt = 0;; ++attempt) {
950 Kokkos::parallel_for(
951 "tess.build", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(
const int pi) {
952 if (binnedV0(pi) >= nBuildL)
956 Kokkos::deep_copy(nFacetsRaw, Kokkos::subview(facetCursor, 0));
958 Kokkos::deep_copy(nEdgesRaw, Kokkos::subview(edgeCursor, 0));
959 const bool facetOver = (size_t)nFacetsRaw > facetCap;
960 const bool edgeOver = withAreaGrad && (size_t)nEdgesRaw > edgeCap;
961 if (!(facetOver || edgeOver) || attempt >= 2)
967 facetCap = (size_t)nFacetsRaw;
969 edgeCap = (size_t)nEdgesRaw;
970 ++overBufferRebuilds;
972 std::fprintf(stderr,
"[tess.build] over-buffer exceeded (facets %d, edges %d): rebuilding\n",
973 nFacetsRaw, nEdgesRaw);
977 op.oNbr = oNbr = Kokkos::View<int*, MemSpace>();
978 op.oArea = oArea = Kokkos::View<Real*, MemSpace>();
979 op.oDV = oDV = Kokkos::View<Real*, MemSpace>();
980 op.oConn = oConn = Kokkos::View<Real*, MemSpace>();
981 op.oEdgeOff = oEdgeOff = Kokkos::View<int*, MemSpace>();
982 op.oEdgeCnt = oEdgeCnt = Kokkos::View<int*, MemSpace>();
983 op.oEdgeFacet = oEdgeFacet = Kokkos::View<int*, MemSpace>();
984 op.oEdgeGrad = oEdgeGrad = Kokkos::View<Real*, MemSpace>();
985 op.oEdgeLen = oEdgeLen = Kokkos::View<Real*, MemSpace>();
986 op.oMoment2 = oMoment2 = Kokkos::View<Real*, MemSpace>();
992 op.facetCap = facetCap;
993 op.oEdgeOff = oEdgeOff;
994 op.oEdgeCnt = oEdgeCnt;
995 op.oEdgeFacet = oEdgeFacet;
996 op.oEdgeGrad = oEdgeGrad;
997 op.oEdgeLen = oEdgeLen;
998 op.edgeCap = edgeCap;
999 op.oMoment2 = oMoment2;
1004 tBuild = ptimer.seconds();
1015 const int nFacets = (size_t)nFacetsRaw > facetCap ? (
int)facetCap : nFacetsRaw;
1017 TessellationView<Real> view;
1018 view.cellFacetOffset = cellFacetBase;
1019 view.cellFacetCount = facetCount;
1020 view.cellVolume = cellVol;
1022 Kokkos::View<gid_t*, MemSpace>(view_alloc(std::string(
"cellSeedId"), WithoutInitializing), N);
1024 auto vSeed = view.cellSeedId;
1025 Kokkos::parallel_for(
1026 "tess.seedId", Kokkos::RangePolicy<Exec>(0, N),
1027 KOKKOS_LAMBDA(
const int i) { vSeed(i) = (
gid_t)i; });
1036 view.facetNeighbor = Kokkos::View<gid_t*, MemSpace>(
1037 view_alloc(std::string(
"facetNeighbor"), WithoutInitializing), nFacets);
1039 auto v = view.facetNeighbor;
1041 Kokkos::parallel_for(
1042 "tess.packNbr", Kokkos::RangePolicy<Exec>(0, nFacets),
1043 KOKKOS_LAMBDA(
const int g) { v(g) = (
gid_t)src(g); });
1046 oNbr = Kokkos::View<int*, MemSpace>();
1048 view.facetArea = Kokkos::View<Real*, MemSpace>(
1049 view_alloc(std::string(
"facetArea"), WithoutInitializing), (
size_t)nFacets * 3);
1051 auto v = view.facetArea;
1053 Kokkos::parallel_for(
1054 "tess.packArea", Kokkos::RangePolicy<Exec>(0, nFacets), KOKKOS_LAMBDA(
const int g) {
1055 for (
int cc = 0; cc < 3; ++cc)
1056 v(3 * g + cc) = src(3 * (
size_t)g + cc);
1060 oArea = Kokkos::View<Real*, MemSpace>();
1062 view.facetConnect = Kokkos::View<Real*, MemSpace>(
1063 view_alloc(std::string(
"facetConnect"), WithoutInitializing), (
size_t)nFacets * 3);
1065 auto v = view.facetConnect;
1067 Kokkos::parallel_for(
1068 "tess.packDV", Kokkos::RangePolicy<Exec>(0, nFacets), KOKKOS_LAMBDA(
const int g) {
1069 for (
int cc = 0; cc < 3; ++cc)
1070 v(3 * g + cc) = src(3 * (
size_t)g + cc);
1074 oDV = Kokkos::View<Real*, MemSpace>();
1076 view.facetConnVec = Kokkos::View<Real*, MemSpace>(
1077 view_alloc(std::string(
"facetConnVec"), WithoutInitializing), (
size_t)nFacets * 3);
1079 auto v = view.facetConnVec;
1081 Kokkos::parallel_for(
1082 "tess.packConn", Kokkos::RangePolicy<Exec>(0, nFacets), KOKKOS_LAMBDA(
const int g) {
1083 for (
int cc = 0; cc < 3; ++cc)
1084 v(3 * g + cc) = src(3 * (
size_t)g + cc);
1090 if (oWallDV.extent(0) > 0) {
1091 view.cellWallDV = oWallDV;
1092 view.cellWallDA = oWallDA;
1095 view.facetMoment2 = Kokkos::View<Real*, MemSpace>(
1096 view_alloc(std::string(
"facetMoment2"), WithoutInitializing), nFacets);
1097 Kokkos::deep_copy(view.facetMoment2, Kokkos::subview(oMoment2, std::make_pair(0, nFacets)));
1100 const int nEdges = (size_t)nEdgesRaw > edgeCap ? (
int)edgeCap : nEdgesRaw;
1101 view.facetEdgeOffset = Kokkos::View<int*, MemSpace>(
1102 view_alloc(std::string(
"facetEdgeOffset"), WithoutInitializing), nFacets);
1103 view.facetEdgeCount = Kokkos::View<int*, MemSpace>(
1104 view_alloc(std::string(
"facetEdgeCount"), WithoutInitializing), nFacets);
1105 Kokkos::deep_copy(view.facetEdgeOffset, Kokkos::subview(oEdgeOff, std::make_pair(0, nFacets)));
1106 Kokkos::deep_copy(view.facetEdgeCount, Kokkos::subview(oEdgeCnt, std::make_pair(0, nFacets)));
1107 view.edgeFacet = Kokkos::View<int*, MemSpace>(
1108 view_alloc(std::string(
"edgeFacet"), WithoutInitializing), nEdges);
1109 view.edgeAreaGrad = Kokkos::View<Real*, MemSpace>(
1110 view_alloc(std::string(
"edgeAreaGrad"), WithoutInitializing), (
size_t)nEdges * 3);
1111 Kokkos::deep_copy(view.edgeFacet, Kokkos::subview(oEdgeFacet, std::make_pair(0, nEdges)));
1112 Kokkos::deep_copy(view.edgeAreaGrad,
1113 Kokkos::subview(oEdgeGrad, std::make_pair((
size_t)0, (
size_t)nEdges * 3)));
1114 view.edgeLength = Kokkos::View<Real*, MemSpace>(
1115 view_alloc(std::string(
"edgeLength"), WithoutInitializing), nEdges);
1117 auto el = view.edgeLength;
1118 auto src = oEdgeLen;
1119 Kokkos::parallel_for(
1120 "edgeLength", Kokkos::RangePolicy<Exec>(0, nEdges),
1121 KOKKOS_LAMBDA(
const int e) { el(e) = src((
size_t)e * 4); });
1125 oConn = Kokkos::View<Real*, MemSpace>();
1128 tCsr = ptimer.seconds();
1129 std::fprintf(stderr,
"[tess N=%d] grid=%.4fs build=%.4fs csr=%.4fs (build %.0f%%)\n", N, tGrid,
1130 tBuild, tCsr, 100.0 * tBuild / (tGrid + tBuild + tCsr));
1134 auto fc = facetCount;
1135 Kokkos::parallel_reduce(
1136 "tess.maxFacets", Kokkos::RangePolicy<Exec>(0, N),
1137 KOKKOS_LAMBDA(
const int c,
int& m) { m = fc(c) > m ? fc(c) : m; }, Kokkos::Max<int>(maxF));
1138 std::fprintf(stderr,
"[tess N=%d] maxFacets/cell=%d (=> maxVerts ~ %d; CAP=%d)\n", N, maxF,
1142 TessellatorResult<Real> res;
1144 res.status = status;
1145 res.overBufferRebuilds = overBufferRebuilds;