103 const Kokkos::View<Real*, peclet::core::MemSpace>& weight,
int N,
104 const Real L[3],
int sw = 4,
int densityCount = -1,
105 Kokkos::View<long*, peclet::core::MemSpace> gid = {},
106 WorklistCache<Real>* wlc =
nullptr) {
107 using peclet::core::MemSpace;
108 using Exec = peclet::core::ExecSpace;
113 const bool haveGid = gid.extent(0) ==
static_cast<size_t>(N);
114 grid.haveGid = haveGid;
126 constexpr bool kHostBackend = Kokkos::SpaceAccessibility<Kokkos::HostSpace, MemSpace>::accessible;
127 constexpr Real kSeedsPerCell = (!Weighted && kHostBackend) ? Real(2) : Real(1);
128 const int dens = densityCount > 0 ? densityCount : N;
129 const Real vol = L[0] * L[1] * L[2];
130 const Real spacing = std::cbrt(kSeedsPerCell * vol / Real(dens > 0 ? dens : 1));
132 Real csz[3], invcsz[3];
133 for (
int k = 0; k < 3; ++k) {
134 dim[k] = (int)Kokkos::floor(L[k] / spacing);
137 csz[k] = L[k] / dim[k];
138 invcsz[k] = Real(1) / csz[k];
140 const int dimx = dim[0], dimy = dim[1], dimz = dim[2];
141 const int ncell = dimx * dimy * dimz;
153 int md = dimx > dimy ? dimx : dimy;
154 md = md > dimz ? md : dimz;
155 while ((1 << mbits) < md)
158 const size_t mortonNcell = (size_t)1 << (3 * mbits);
159 const bool useMorton = !kHostBackend && mortonNcell <= (size_t)8 * (
size_t)ncell;
160 const int ncellEff = useMorton ? (int)mortonNcell : ncell;
162 const Real Lx = L[0], Ly = L[1], Lz = L[2];
163 const Real icx = invcsz[0], icy = invcsz[1], icz = invcsz[2];
164 Real minCsz = csz[0] < csz[1] ? csz[0] : csz[1];
165 minCsz = minCsz < csz[2] ? minCsz : csz[2];
172 grid.minCsz = minCsz;
176 grid.useMorton = useMorton;
179 Kokkos::View<int*, MemSpace> cellOf(
"cellOf", N);
180 Kokkos::View<int*, MemSpace> counts(
"counts", ncellEff + 1);
181 Kokkos::deep_copy(counts, 0);
182 Kokkos::parallel_for(
183 "tess.bin", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(
const int i) {
184 int gx = (int)Kokkos::floor(posFlat(3 * i + 0) * icx);
185 int gy = (int)Kokkos::floor(posFlat(3 * i + 1) * icy);
186 int gz = (int)Kokkos::floor(posFlat(3 * i + 2) * icz);
187 gx = ((gx % dimx) + dimx) % dimx;
188 gy = ((gy % dimy) + dimy) % dimy;
189 gz = ((gz % dimz) + dimz) % dimz;
190 int c = useMorton ?
morton3(gx, gy, gz) : (gx + gy * dimx + gz * dimx * dimy);
192 Kokkos::atomic_inc(&counts(c));
195 Kokkos::View<int*, MemSpace> cellStart(
"cellStart", ncellEff + 1);
196 Kokkos::parallel_scan(
197 "tess.scan", Kokkos::RangePolicy<Exec>(0, ncellEff + 1),
198 KOKKOS_LAMBDA(
const int c,
int& acc,
const bool fin) {
199 int v = (c < ncellEff) ? counts(c) : 0;
205 Kokkos::View<int*, MemSpace> cursor(
"cursor", ncellEff);
206 Kokkos::parallel_for(
207 "tess.cursor", Kokkos::RangePolicy<Exec>(0, ncellEff),
208 KOKKOS_LAMBDA(
const int c) { cursor(c) = cellStart(c); });
209 Kokkos::View<int*, MemSpace> binned(
"binned", N);
210 Kokkos::parallel_for(
211 "tess.scatter", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(
const int i) {
212 int slot = Kokkos::atomic_fetch_add(&cursor(cellOf(i)), 1);
222 using Kokkos::view_alloc;
223 using Kokkos::WithoutInitializing;
224 Kokkos::View<Real*, MemSpace> posSorted(view_alloc(std::string(
"posSorted"), WithoutInitializing),
226 Kokkos::View<int*, MemSpace> slotOf(view_alloc(std::string(
"slotOf"), WithoutInitializing), N);
227 Kokkos::View<gid_t*, MemSpace> gidSorted(
228 view_alloc(std::string(
"gidSorted"), WithoutInitializing), haveGid ? N : 0);
229 Kokkos::View<Real*, MemSpace> wSorted(view_alloc(std::string(
"wSorted"), WithoutInitializing),
232 const bool haveGidL = haveGid;
233 Kokkos::parallel_for(
234 "tess.reorder", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(
const int p) {
237 posSorted(3 * p + 0) = posFlat(3 * o + 0);
238 posSorted(3 * p + 1) = posFlat(3 * o + 1);
239 posSorted(3 * p + 2) = posFlat(3 * o + 2);
241 gidSorted(p) = gid(o);
243 wSorted(p) = weight(o);
246 grid.binned = binned;
247 grid.slotOf = slotOf;
248 grid.posSorted = posSorted;
249 grid.gidSorted = gidSorted;
250 grid.wSorted = wSorted;
251 grid.cellStart = cellStart;
258 std::vector<int> offHx, offHy, offHz;
260 const int swInit = sw < 2 ? sw : 2;
261 const int sw2 = sw * sw;
262 for (
int swl = swInit; swl <= sw; ++swl) {
263 const int lo2 = (swl == swInit) ? -1 : (swl - 1) * (swl - 1);
264 const int hi2 = swl * swl;
265 for (
int dz = -(swl + 1); dz <= swl + 1; ++dz) {
266 const int ez = dz < -1 ? -dz - 1 : (dz > 1 ? dz - 1 : 0);
267 for (
int dy = -(swl + 1); dy <= swl + 1; ++dy) {
268 const int ey = dy < -1 ? -dy - 1 : (dy > 1 ? dy - 1 : 0);
269 for (
int dx = -(swl + 1); dx <= swl + 1; ++dx) {
270 const int ex = dx < -1 ? -dx - 1 : (dx > 1 ? dx - 1 : 0);
271 const int d2 = ex * ex + ey * ey + ez * ez;
272 if (d2 <= lo2 || d2 > hi2 || d2 > sw2)
282 const int nOff = (int)offHx.size();
284 const int nSub = wlS * wlS * wlS;
289 if (wlc && wlc->matches(grid.dimx, grid.dimy, grid.dimz, sw, csz[0], csz[1], csz[2])) {
290 grid.wlOff = wlc->wlOff;
291 grid.wlRmin = wlc->wlRmin;
294 Kokkos::View<int*, MemSpace> wlOff(view_alloc(std::string(
"wlOff"), WithoutInitializing),
295 (
size_t)nSub * nOff);
296 Kokkos::View<Real*, MemSpace> wlRmin(view_alloc(std::string(
"wlRmin"), WithoutInitializing),
297 (
size_t)nSub * nOff);
299 auto hOff = Kokkos::create_mirror_view(wlOff);
300 auto hRmin = Kokkos::create_mirror_view(wlRmin);
301 const Real cszx = csz[0], cszy = csz[1], cszz = csz[2];
303 auto axisGap = [](Real a0, Real a1, Real b0, Real b1) {
304 Real g = std::max(Real(0), std::max(b0 - a1, a0 - b1));
307 std::vector<int> idx(nOff);
308 std::vector<Real> rmn(nOff);
309 for (
int sz = 0; sz < wlS; ++sz)
310 for (
int sy = 0; sy < wlS; ++sy)
311 for (
int sx = 0; sx < wlS; ++sx) {
312 const int p = sx + wlS * (sy + wlS * sz);
313 const Real ax0 = (Real)sx / wlS * cszx, ax1 = (Real)(sx + 1) / wlS * cszx;
314 const Real ay0 = (Real)sy / wlS * cszy, ay1 = (Real)(sy + 1) / wlS * cszy;
315 const Real az0 = (Real)sz / wlS * cszz, az1 = (Real)(sz + 1) / wlS * cszz;
316 for (
int k = 0; k < nOff; ++k) {
317 const Real bx0 = offHx[k] * cszx, bx1 = (offHx[k] + 1) * cszx;
318 const Real by0 = offHy[k] * cszy, by1 = (offHy[k] + 1) * cszy;
319 const Real bz0 = offHz[k] * cszz, bz1 = (offHz[k] + 1) * cszz;
320 rmn[k] = axisGap(ax0, ax1, bx0, bx1) + axisGap(ay0, ay1, by0, by1) +
321 axisGap(az0, az1, bz0, bz1);
324 std::sort(idx.begin(), idx.end(), [&](
int a,
int b) { return rmn[a] < rmn[b]; });
325 for (
int g = 0; g < nOff; ++g) {
326 const int k = idx[g];
327 const size_t slot = (size_t)p * nOff + g;
330 hRmin(slot) = rmn[k];
333 Kokkos::deep_copy(wlOff, hOff);
334 Kokkos::deep_copy(wlRmin, hRmin);
337 grid.wlRmin = wlRmin;
340 wlc->wlRmin = wlRmin;
343 wlc->dimx = grid.dimx;
344 wlc->dimy = grid.dimy;
345 wlc->dimz = grid.dimz;