104 const Kokkos::View<Real*, peclet::core::MemSpace>& weight,
int N,
105 const Real L[3],
int sw =
kSearchWindow,
int densityCount = -1,
106 Kokkos::View<long*, peclet::core::MemSpace> gid = {},
107 WorklistCache<Real>* wlc =
nullptr) {
108 using peclet::core::MemSpace;
109 using Exec = peclet::core::ExecSpace;
114 const bool haveGid = gid.extent(0) ==
static_cast<size_t>(N);
115 grid.haveGid = haveGid;
127 constexpr bool kHostBackend = Kokkos::SpaceAccessibility<Kokkos::HostSpace, MemSpace>::accessible;
128 constexpr Real kSeedsPerCell = (!Weighted && kHostBackend) ? Real(2) : Real(1);
129 const int dens = densityCount > 0 ? densityCount : N;
130 const Real vol = L[0] * L[1] * L[2];
131 const Real spacing = std::cbrt(kSeedsPerCell * vol / Real(dens > 0 ? dens : 1));
133 Real csz[3], invcsz[3];
134 for (
int k = 0; k < 3; ++k) {
135 dim[k] = (int)Kokkos::floor(L[k] / spacing);
138 csz[k] = L[k] / dim[k];
139 invcsz[k] = Real(1) / csz[k];
141 const int dimx = dim[0], dimy = dim[1], dimz = dim[2];
146 const int minDim = std::min({dimx, dimy, dimz});
147 const int swMax = std::max(1, (minDim - 1) / 2 - 1);
152 const int ncell = dimx * dimy * dimz;
164 int md = dimx > dimy ? dimx : dimy;
165 md = md > dimz ? md : dimz;
166 while ((1 << mbits) < md)
169 const size_t mortonNcell = (size_t)1 << (3 * mbits);
170 const bool useMorton = !kHostBackend && mortonNcell <= (size_t)8 * (
size_t)ncell;
171 const int ncellEff = useMorton ? (int)mortonNcell : ncell;
173 const Real Lx = L[0], Ly = L[1], Lz = L[2];
174 const Real icx = invcsz[0], icy = invcsz[1], icz = invcsz[2];
175 Real minCsz = csz[0] < csz[1] ? csz[0] : csz[1];
176 minCsz = minCsz < csz[2] ? minCsz : csz[2];
183 grid.minCsz = minCsz;
187 grid.useMorton = useMorton;
190 Kokkos::View<int*, MemSpace> cellOf(
"cellOf", N);
191 Kokkos::View<int*, MemSpace> counts(
"counts", ncellEff + 1);
192 Kokkos::deep_copy(counts, 0);
193 Kokkos::parallel_for(
194 "tess.bin", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(
const int i) {
195 int gx = (int)Kokkos::floor(posFlat(3 * i + 0) * icx);
196 int gy = (int)Kokkos::floor(posFlat(3 * i + 1) * icy);
197 int gz = (int)Kokkos::floor(posFlat(3 * i + 2) * icz);
198 gx = ((gx % dimx) + dimx) % dimx;
199 gy = ((gy % dimy) + dimy) % dimy;
200 gz = ((gz % dimz) + dimz) % dimz;
201 int c = useMorton ?
morton3(gx, gy, gz) : (gx + gy * dimx + gz * dimx * dimy);
203 Kokkos::atomic_inc(&counts(c));
206 Kokkos::View<int*, MemSpace> cellStart(
"cellStart", ncellEff + 1);
207 Kokkos::parallel_scan(
208 "tess.scan", Kokkos::RangePolicy<Exec>(0, ncellEff + 1),
209 KOKKOS_LAMBDA(
const int c,
int& acc,
const bool fin) {
210 int v = (c < ncellEff) ? counts(c) : 0;
216 Kokkos::View<int*, MemSpace> cursor(
"cursor", ncellEff);
217 Kokkos::parallel_for(
218 "tess.cursor", Kokkos::RangePolicy<Exec>(0, ncellEff),
219 KOKKOS_LAMBDA(
const int c) { cursor(c) = cellStart(c); });
220 Kokkos::View<int*, MemSpace> binned(
"binned", N);
221 Kokkos::parallel_for(
222 "tess.scatter", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(
const int i) {
223 int slot = Kokkos::atomic_fetch_add(&cursor(cellOf(i)), 1);
233 using Kokkos::view_alloc;
234 using Kokkos::WithoutInitializing;
235 Kokkos::View<Real*, MemSpace> posSorted(view_alloc(std::string(
"posSorted"), WithoutInitializing),
237 Kokkos::View<int*, MemSpace> slotOf(view_alloc(std::string(
"slotOf"), WithoutInitializing), N);
238 Kokkos::View<gid_t*, MemSpace> gidSorted(
239 view_alloc(std::string(
"gidSorted"), WithoutInitializing), haveGid ? N : 0);
240 Kokkos::View<Real*, MemSpace> wSorted(view_alloc(std::string(
"wSorted"), WithoutInitializing),
243 const bool haveGidL = haveGid;
244 Kokkos::parallel_for(
245 "tess.reorder", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(
const int p) {
248 posSorted(3 * p + 0) = posFlat(3 * o + 0);
249 posSorted(3 * p + 1) = posFlat(3 * o + 1);
250 posSorted(3 * p + 2) = posFlat(3 * o + 2);
252 gidSorted(p) = gid(o);
254 wSorted(p) = weight(o);
257 grid.binned = binned;
258 grid.slotOf = slotOf;
259 grid.posSorted = posSorted;
260 grid.gidSorted = gidSorted;
261 grid.wSorted = wSorted;
262 grid.cellStart = cellStart;
269 std::vector<int> offHx, offHy, offHz;
271 const int swInit = sw < 2 ? sw : 2;
272 const int sw2 = sw * sw;
273 for (
int swl = swInit; swl <= sw; ++swl) {
274 const int lo2 = (swl == swInit) ? -1 : (swl - 1) * (swl - 1);
275 const int hi2 = swl * swl;
276 for (
int dz = -(swl + 1); dz <= swl + 1; ++dz) {
277 const int ez = dz < -1 ? -dz - 1 : (dz > 1 ? dz - 1 : 0);
278 for (
int dy = -(swl + 1); dy <= swl + 1; ++dy) {
279 const int ey = dy < -1 ? -dy - 1 : (dy > 1 ? dy - 1 : 0);
280 for (
int dx = -(swl + 1); dx <= swl + 1; ++dx) {
281 const int ex = dx < -1 ? -dx - 1 : (dx > 1 ? dx - 1 : 0);
282 const int d2 = ex * ex + ey * ey + ez * ez;
283 if (d2 <= lo2 || d2 > hi2 || d2 > sw2)
293 const int nOff = (int)offHx.size();
295 const int nSub = wlS * wlS * wlS;
300 if (wlc && wlc->matches(grid.dimx, grid.dimy, grid.dimz, sw, csz[0], csz[1], csz[2])) {
301 grid.wlOff = wlc->wlOff;
302 grid.wlRmin = wlc->wlRmin;
305 Kokkos::View<int*, MemSpace> wlOff(view_alloc(std::string(
"wlOff"), WithoutInitializing),
306 (
size_t)nSub * nOff);
307 Kokkos::View<Real*, MemSpace> wlRmin(view_alloc(std::string(
"wlRmin"), WithoutInitializing),
308 (
size_t)nSub * nOff);
310 auto hOff = Kokkos::create_mirror_view(wlOff);
311 auto hRmin = Kokkos::create_mirror_view(wlRmin);
312 const Real cszx = csz[0], cszy = csz[1], cszz = csz[2];
314 auto axisGap = [](Real a0, Real a1, Real b0, Real b1) {
315 Real g = std::max(Real(0), std::max(b0 - a1, a0 - b1));
318 std::vector<int> idx(nOff);
319 std::vector<Real> rmn(nOff);
320 for (
int sz = 0; sz < wlS; ++sz)
321 for (
int sy = 0; sy < wlS; ++sy)
322 for (
int sx = 0; sx < wlS; ++sx) {
323 const int p = sx + wlS * (sy + wlS * sz);
324 const Real ax0 = (Real)sx / wlS * cszx, ax1 = (Real)(sx + 1) / wlS * cszx;
325 const Real ay0 = (Real)sy / wlS * cszy, ay1 = (Real)(sy + 1) / wlS * cszy;
326 const Real az0 = (Real)sz / wlS * cszz, az1 = (Real)(sz + 1) / wlS * cszz;
327 for (
int k = 0; k < nOff; ++k) {
328 const Real bx0 = offHx[k] * cszx, bx1 = (offHx[k] + 1) * cszx;
329 const Real by0 = offHy[k] * cszy, by1 = (offHy[k] + 1) * cszy;
330 const Real bz0 = offHz[k] * cszz, bz1 = (offHz[k] + 1) * cszz;
331 rmn[k] = axisGap(ax0, ax1, bx0, bx1) + axisGap(ay0, ay1, by0, by1) +
332 axisGap(az0, az1, bz0, bz1);
335 std::sort(idx.begin(), idx.end(), [&](
int a,
int b) { return rmn[a] < rmn[b]; });
336 for (
int g = 0; g < nOff; ++g) {
337 const int k = idx[g];
338 const size_t slot = (size_t)p * nOff + g;
341 hRmin(slot) = rmn[k];
344 Kokkos::deep_copy(wlOff, hOff);
345 Kokkos::deep_copy(wlRmin, hRmin);
348 grid.wlRmin = wlRmin;
351 wlc->wlRmin = wlRmin;
354 wlc->dimx = grid.dimx;
355 wlc->dimy = grid.dimy;
356 wlc->dimz = grid.dimz;