30 S
x = S(),
y = S(),
z = S();
32 void get(
const S* p) {
33 x = p[0],
y = p[1],
z = p[2];
36 p[0] =
x, p[1] =
y, p[2] =
z;
53 template<
class T,
class S>
60 template<
class T,
class S>
65 std::vector<elem<T,S> > *
elems = NULL;
78 double log_two = log(val) / log(2.0);
79 int log_two_int = log_two;
81 return (fabs(
double(log_two_int) - log_two) < 1e-6);
92 template<
class T,
class S>
99 template<
class T,
class S>
102 return lhs.
v1 < rhs.
v1;
116 template<
typename V,
typename W>
117 V
clamp(
const V val,
const W start,
const W end) {
118 if(val < start)
return start;
119 if(val > end)
return end;
125 inline void dsp_from_cnt(
const std::vector<T> & cnt, std::vector<T> & dsp)
127 dsp.resize(cnt.size()+1);
129 for(
size_t i=0; i<cnt.size(); i++) dsp[i+1] = dsp[i] + cnt[i];
134 inline void cnt_from_dsp(
const std::vector<T> & dsp, std::vector<T> & cnt)
136 cnt.resize(dsp.size() - 1);
137 for(
size_t i=0; i<dsp.size()-1; i++) cnt[i] = dsp[i+1] - dsp[i];
140 template<
class V,
class W>
141 void sort_copy(std::vector<V> & v1, std::vector<W> & v2)
143 assert(v1.size() == v2.size());
145 std::vector<mixed_pair<V,W> > pair_array(v1.size());
147 for(
size_t i=0; i<v1.size(); i++) {
148 pair_array[i].v1 = v1[i];
149 pair_array[i].v2 = v2[i];
152 std::sort(pair_array.begin(), pair_array.end());
154 for(
size_t i=0; i<v1.size(); i++) {
155 v1[i] = pair_array[i].v1;
156 v2[i] = pair_array[i].v2;
170 #define KD_ORDER_INC 5.0
172 #define KD_MIN_SIZE 64
175 template<
class T,
class S>
180 std::vector<kdpart::partition<T,S> > _layout;
187 double minmax[6], minmax_red[6];
196 for(
size_t i=0; i<elems.size(); i++) {
199 if(minmax[0] > p.
x) minmax[0] = p.
x;
200 if(minmax[1] > p.
y) minmax[1] = p.
y;
201 if(minmax[2] > p.
z) minmax[2] = p.
z;
202 if(minmax[3] < p.
x) minmax[3] = p.
x;
203 if(minmax[4] < p.
y) minmax[4] = p.
y;
204 if(minmax[5] < p.
z) minmax[5] = p.
z;
207 MPI_Allreduce(minmax, minmax_red, 3, MPI_DOUBLE, MPI_MIN, _comm);
208 MPI_Allreduce(minmax+3, minmax_red+3, 3, MPI_DOUBLE, MPI_MAX, _comm);
214 min.x = minmax_red[0];
215 min.y = minmax_red[1];
216 min.z = minmax_red[2];
217 max.x = minmax_red[3];
218 max.y = minmax_red[4];
219 max.z = minmax_red[5];
230 S x = fabs(
min.x -
max.x);
231 S y = fabs(
min.y -
max.y);
232 S z = fabs(
min.z -
max.z);
234 return x > y && x > z ?
X : y > z ?
Y :
Z;
244 inline void print_layout(
const T split_pos = -1)
246 int rank; MPI_Comm_rank(_comm, &rank);
248 if(rank != 0)
return;
252 while(idx < split_pos) {
253 printf(
"%d : %d \n",
int(_layout[idx].pidx),
int(_layout[idx].cnt));
258 printf(
"%d : %d \n",
int(_layout[idx].pidx),
int(_layout[idx].cnt));
259 printf(
"%d : %d \n",
int(_layout[idx+1].pidx),
int(_layout[idx+1].cnt));
263 while(
size_t(idx) < _layout.size() && _layout[idx].pidx > -1) {
264 printf(
"%d : %d \n",
int(_layout[idx].pidx),
int(_layout[idx].cnt));
271 while(
size_t(idx) < _layout.size() && _layout[idx].pidx > -1) {
272 printf(
"%d : %d \n",
int(_layout[idx].pidx),
int(_layout[idx].cnt));
279 inline void get_parallel_median_split(std::vector<
mixed_pair<S,T>> & vals,
281 std::vector<bool> & on_left_side)
284 MPI_Comm_size(_comm, &size);
285 MPI_Comm_rank(_comm, &rank);
287 on_left_side.resize(vals.size());
288 std::sort(vals.begin(), vals.end());
290 size_t nelem = vals.size();
291 double bucket_size = (
max*1.05 -
min) /
double(size);
292 std::vector<int> buckets(
size_t(size),
int(0));
293 for(
size_t i=0; i<nelem; i++) {
294 int idx = (vals[i].v1 -
min) / bucket_size;
299 std::vector<int> glob_buckets(
size_t(size),
int(0));
300 MPI_Allreduce(buckets.data(), glob_buckets.data(), size, MPI_INT, MPI_SUM, _comm);
303 int glob_sum = std::accumulate(glob_buckets.begin(), glob_buckets.end(), 0);
304 int lhalf = (glob_sum + 1) / 2;
306 int dsp = 0, bucket_idx = 0;
307 while(bucket_idx < size && (dsp + glob_buckets[bucket_idx]) <= lhalf) {
308 dsp += glob_buckets[bucket_idx];
314 if(bucket_idx < 0 || bucket_idx >= size) {
315 fprintf(stderr,
"Error: Illegal bucket index !!\n");
319 std::vector<double> loc_val_bucket, glob_val_bucket;
321 std::vector<short> global_split_bucket, split_bucket(buckets[bucket_idx]);
323 loc_val_bucket.resize(buckets[bucket_idx]);
324 for(
size_t i=0, widx=0; i<nelem; i++) {
325 int idx = (vals[i].v1 -
min) / bucket_size;
328 if(idx == bucket_idx)
329 loc_val_bucket[widx++] = vals[i].v1;
332 std::vector<int> rcnt(size), rdsp(size);
333 MPI_Gather(&buckets[bucket_idx], 1, MPI_INT, rcnt.data(), 1, MPI_INT, bucket_idx, _comm);
336 if(rank == bucket_idx) {
337 glob_val_bucket.resize(glob_buckets[bucket_idx]);
338 global_split_bucket.resize(glob_buckets[bucket_idx]);
342 MPI_Gatherv(loc_val_bucket.data(), buckets[bucket_idx], MPI_DOUBLE,
343 glob_val_bucket.data(), rcnt.data(), rdsp.data(), MPI_DOUBLE,
349 if(rank == bucket_idx) {
350 size_t bsize = glob_val_bucket.size();
352 std::vector<int> bucket_perm(bsize);
353 for(
size_t i=0; i<bsize; i++) bucket_perm[i] = i;
356 int loc_half_idx = lhalf - dsp;
359 if(loc_half_idx < 0 || loc_half_idx >=
int(glob_val_bucket.size())) {
360 fprintf(stderr,
"Error: Illegal local val index!!\n");
363 for(
int i=0; i <= loc_half_idx; i++)
364 global_split_bucket[bucket_perm[i]] = 1;
366 for(
int i=loc_half_idx+1; i < int(bsize); i++)
367 global_split_bucket[bucket_perm[i]] = 0;
370 MPI_Scatterv(global_split_bucket.data(), rcnt.data(), rdsp.data(), MPI_SHORT,
371 split_bucket.data(), buckets[bucket_idx], MPI_SHORT,
374 for(
size_t i=0, ridx=0; i<nelem; i++) {
375 int pidx = vals[i].v2;
376 int idx = (vals[i].v1 -
min) / bucket_size;
380 on_left_side[pidx] =
true;
381 else if(idx == bucket_idx)
382 on_left_side[pidx] = split_bucket[ridx++] == 1;
384 on_left_side[pidx] =
false;
400 size_t nelem = parent.
elems->size();
402 std::vector<mixed_pair<S,T>> vals(nelem);
405 switch(longest_axis) {
407 min = parent.
box.bounds[0].x,
max = parent.
box.bounds[1].x;
408 for(
size_t i=0; i<nelem; i++) {
416 min = parent.
box.bounds[0].y,
max = parent.
box.bounds[1].y;
417 for(
size_t i=0; i<nelem; i++) {
425 min = parent.
box.bounds[0].z,
max = parent.
box.bounds[1].z;
426 for(
size_t i=0; i<nelem; i++) {
437 std::vector<bool> on_left;
438 get_parallel_median_split(vals,
min,
max, on_left);
441 size_t left_size = 0, right_size = 0;
443 for(
size_t i=0; i<nelem; i++) {
444 if(on_left[i]) left_size++;
448 lchild.
elems =
new std::vector<elem<T,S> >(left_size), rchild.
elems =
new std::vector<
elem<T,S> >(right_size);
450 left_size = 0, right_size = 0;
451 for(
size_t i=0; i<nelem; i++) {
452 if(on_left[i]) (*lchild.
elems)[left_size++ ] = (*parent.
elems)[i];
453 else (*rchild.
elems)[right_size++] = (*parent.
elems)[i];
460 int buff[2] = {int(lchild.
elems->size()), int(rchild.
elems->size())};
461 MPI_Allreduce(MPI_IN_PLACE, buff, 2, MPI_INT, MPI_SUM, _comm);
462 lchild.
cnt = buff[0], rchild.
cnt = buff[1];
464 if(lchild.
cnt == 0 || rchild.
cnt == 0) {
465 fprintf(stderr,
"Error: Empty partitioning!!\n");
468 lchild.
box = get_bbox(*lchild.
elems);
469 rchild.
box = get_bbox(*rchild.
elems);
477 inline void update_layout(
const T split_pos) {
478 assert(
size_t(split_pos) < _layout.size());
480 T idx_at_split = _layout[split_pos].pidx;
481 T start = _cur_part_number - 1, stop = split_pos + 1;
484 for(T i = start; i > stop; i--) {
485 _layout[i] = _layout[i-1];
490 median_split(_layout[split_pos], _layout[split_pos], _layout[split_pos+1]);
491 _layout[split_pos].pidx = idx_at_split;
492 _layout[split_pos+1].pidx = idx_at_split+1;
503 inline T get_split_pos()
505 T idx = 0,
max = _layout[0].cnt, maxidx = 0;
507 while(idx < _cur_part_number && _layout[idx].cnt > -1) {
508 if(
max < _layout[idx].cnt) {
509 max = _layout[idx].cnt;
519 inline void operator() (
const MPI_Comm comm,
const std::vector<S> & ctr,
const int req_part,
520 std::vector<T> & part_vec)
524 assert(ctr.size() % 3 == 0);
527 long int l_numelem = ctr.size() / 3, g_numelem;
528 MPI_Allreduce(&l_numelem, &g_numelem, 1, MPI_LONG, MPI_SUM, _comm);
529 assert(g_numelem > 0);
532 MPI_Comm_size(_comm, &size); MPI_Comm_rank(_comm, &rank);
536 bool redistribute_remainder =
false;
548 npart = pow(2, npart);
554 redistribute_remainder =
true;
557 assert(g_numelem > (
long int)npart);
560 _cur_part_number = 1;
561 _layout.resize(
size_t(npart));
563 _layout[0].elems =
new std::vector<kdpart::elem<T,S> >(l_numelem);
564 _layout[0].cnt = g_numelem;
566 std::vector<kdpart::elem<T,S> > & elems = *_layout[0].elems;
569 for(
long int i=0; i<l_numelem; i++) {
570 elems[i].ctr.get(ctr.data() + i*3);
574 _layout[0].box = get_bbox(elems);
582 while(_cur_part_number < npart) {
583 T split_pos = get_split_pos();
586 update_layout(split_pos);
592 if(redistribute_remainder) {
594 T base_size = npart / npart_old;
597 T extended_size = base_size + 1;
598 T remainder = npart % npart_old;
601 for(T i=0; i<remainder; i++) {
602 for(T j=0; j<extended_size; j++)
603 _layout[i*extended_size+j].pidx = i;
607 for(T i=remainder*extended_size, pidx=remainder; i<T(_layout.size()); i+=base_size, pidx++) {
608 for(T j=0; j<base_size; j++)
609 _layout[i+j].pidx = pidx;
616 part_vec.assign(l_numelem, T(-1));
619 part_vec[e.eidx] = p.pidx;
626 template<
class T,
class S>
631 std::vector<kdpart::partition<T,S> > _layout;
645 for(
size_t i=1; i<elems.size(); i++) {
665 S x = fabs(
min.x -
max.x);
666 S y = fabs(
min.y -
max.y);
667 S z = fabs(
min.z -
max.z);
669 return x > y && x > z ?
X : y > z ?
Y :
Z;
679 inline void print_layout(
const T split_pos = -1)
683 while(idx < split_pos) {
684 printf(
"%d : %d \n",
int(_layout[idx].pidx),
int(_layout[idx].cnt));
689 printf(
"%d : %d \n",
int(_layout[idx].pidx),
int(_layout[idx].cnt));
690 printf(
"%d : %d \n",
int(_layout[idx+1].pidx),
int(_layout[idx+1].cnt));
694 while(
size_t(idx) < _layout.size() && _layout[idx].pidx > -1) {
695 printf(
"%d : %d \n",
int(_layout[idx].pidx),
int(_layout[idx].cnt));
702 while(
size_t(idx) < _layout.size() && _layout[idx].pidx > -1) {
703 printf(
"%d : %d \n",
int(_layout[idx].pidx),
int(_layout[idx].cnt));
722 size_t nelem = parent.
elems->size();
725 std::vector<mixed_pair<S,T> > pairs(nelem);
726 for(
size_t i=0; i<nelem; i++) {
729 switch(longest_axis) {
730 case X: val = p.
x;
break;
731 case Y: val = p.
y;
break;
732 case Z: val = p.
z;
break;
736 pairs[i] = {val, T(i)};
738 std::sort(pairs.begin(), pairs.end());
742 size_t lnum = (nelem + 1) / 2, rnum = nelem - lnum;
743 lchild.
elems =
new std::vector<elem<T,S> >(lnum), rchild.
elems =
new std::vector<
elem<T,S> >(rnum);
745 for(
size_t i=0; i<lnum; i++) {
746 T lidx = pairs[i].v2;
750 for(
size_t i=0; i<rnum; i++) {
751 T lidx = pairs[lnum + i].v2;
761 lchild.
box = get_bbox(*lchild.
elems);
762 rchild.
box = get_bbox(*rchild.
elems);
770 inline void update_layout(
const T split_pos) {
771 assert(
size_t(split_pos) < _layout.size());
773 T idx_at_split = _layout[split_pos].pidx;
774 T start = _cur_part_number - 1, stop = split_pos + 1;
777 for(T i = start; i > stop; i--) {
778 _layout[i] = _layout[i-1];
783 median_split(_layout[split_pos], _layout[split_pos], _layout[split_pos+1]);
784 _layout[split_pos].pidx = idx_at_split;
785 _layout[split_pos+1].pidx = idx_at_split+1;
796 inline T get_split_pos()
798 T idx = 0,
max = _layout[0].cnt, maxidx = 0;
800 while(idx < _cur_part_number && _layout[idx].cnt > -1) {
801 if(
max < _layout[idx].cnt) {
802 max = _layout[idx].cnt;
812 inline void operator() (
const std::vector<S> & ctr, T npart, std::vector<T> & part_vec)
814 assert(ctr.size() % 3 == 0);
816 size_t nelem = ctr.size() / 3;
817 assert(nelem >
size_t(npart));
819 bool redistribute_remainder =
false;
830 npart = (log(
double(npart)) / log(2.0)) + 5.0;
831 npart = pow(2, npart);
837 redistribute_remainder =
true;
841 _layout.resize(
size_t(npart));
842 part_vec.assign(nelem, T(-1));
844 _cur_part_number = 1;
846 _layout[0].elems =
new std::vector<kdpart::elem<T,S> >(nelem);
847 std::vector<kdpart::elem<T,S> > & elems = *_layout[0].elems;
849 for(
size_t i=0; i<nelem; i++) {
850 elems[i].ctr.get(ctr.data() + i*3);
854 _layout[0].box = get_bbox(elems);
857 while(_cur_part_number < npart) {
858 T split_pos = get_split_pos();
861 update_layout(split_pos);
864 if(redistribute_remainder) {
865 T base_size = npart / npart_old, extended_size = base_size + 1;
866 T remainder = npart % npart_old;
868 for(T i=0; i<remainder; i++) {
869 for(T j=0; j<extended_size; j++)
870 _layout[i*extended_size+j].pidx = i;
874 for(T i=remainder*extended_size, pidx=remainder; i<T(_layout.size()); i+=base_size, pidx++) {
875 for(T j=0; j<base_size; j++)
876 _layout[i+j].pidx = pidx;
885 part_vec[e.eidx] = p.pidx;
void operator()(const MPI_Comm comm, const std::vector< S > &ctr, const int req_part, std::vector< T > &part_vec)
void operator()(const std::vector< S > &ctr, T npart, std::vector< T > &part_vec)
#define KD_ORDER_INC
The value we add to the power of two if we need higher partitioning resolution.
void sort_copy(std::vector< V > &v1, std::vector< W > &v2)
V clamp(const V val, const W start, const W end)
Clamp a value into an interval [start, end].
bool operator<(const mixed_pair< T, S > &lhs, const mixed_pair< T, S > &rhs)
sorting operator
void cnt_from_dsp(const std::vector< T > &dsp, std::vector< T > &cnt)
Compute counts from displacements.
bool is_power_of_two(double val)
Check if a given value is an integer power of two.
void dsp_from_cnt(const std::vector< T > &cnt, std::vector< T > &dsp)
Compute displacements from counts.
constexpr T min(T a, T b)
constexpr T max(T a, T b)
kdpart::vec3< S > bounds[2]
the bounds. bounds[0] = lower left (min), bounds[1] = upper right (max)
vec3< S > ctr
element center location
Combined floating point and integer pair.
the struct holding all partition data
kdpart::bbox< S > box
(global) partition bounding box
T cnt
(global) partition size
std::vector< elem< T, S > > * elems
(local) elements in partition
minimalistic internal point struct