1 #ifndef DIY_DECOMPOSITION_HPP
2 #define DIY_DECOMPOSITION_HPP
12 #include "assigner.hpp"
19 template<
class Bounds_,
class Enable =
void>
23 template<
class Bounds>
24 struct BoundsHelper<Bounds, typename std::enable_if<std::is_integral<typename Bounds::Coordinate>::value>::type>
26 using Coordinate =
typename Bounds::Coordinate;
28 static Coordinate from(
int i,
int n, Coordinate min, Coordinate max,
bool) {
return min + (max - min + 1)/n * i; }
29 static Coordinate to (
int i,
int n, Coordinate min, Coordinate max,
bool shared_face)
34 return from(i+1, n, min, max, shared_face) - (shared_face ? 0 : 1);
37 static int lower(Coordinate x,
int n, Coordinate min, Coordinate max,
bool shared)
39 Coordinate width = (max - min + 1)/n;
40 Coordinate res = (x - min)/width;
41 if (res >= n) res = n - 1;
43 if (shared && x == from(res, n, min, max, shared))
47 static int upper(Coordinate x,
int n, Coordinate min, Coordinate max,
bool shared)
49 Coordinate width = (max - min + 1)/n;
50 Coordinate res = (x - min)/width + 1;
51 if (shared && x == from(res, n, min, max, shared))
58 template<
class Bounds>
59 struct BoundsHelper<Bounds, typename std::enable_if<std::is_floating_point<typename Bounds::Coordinate>::value>::type>
61 using Coordinate =
typename Bounds::Coordinate;
63 static Coordinate from(
int i,
int n, Coordinate min, Coordinate max,
bool) {
return min + (max - min)/n * i; }
64 static Coordinate to (
int i,
int n, Coordinate min, Coordinate max,
bool) {
return min + (max - min)/n * (i+1); }
66 static int lower(Coordinate x,
int n, Coordinate min, Coordinate max,
bool) { Coordinate width = (max - min)/n; Coordinate res = std::floor((x - min)/width);
if (min + res*width == x)
return (res - 1);
else return res; }
67 static int upper(Coordinate x,
int n, Coordinate min, Coordinate max,
bool) { Coordinate width = (max - min)/n; Coordinate res = std::ceil ((x - min)/width);
if (min + res*width == x)
return (res + 1);
else return res; }
74 template<
class Bounds_>
77 typedef Bounds_ Bounds;
78 typedef typename BoundsValue<Bounds>::type Coordinate;
81 using Creator = std::function<void(int, Bounds, Bounds, Bounds, Link)>;
82 using Updater = std::function<void(int, int, Bounds, Bounds, Bounds, Link)>;
84 typedef std::vector<bool> BoolVector;
85 typedef std::vector<Coordinate> CoordinateVector;
86 typedef std::vector<int> DivisionsVector;
97 const Bounds& domain_,
99 BoolVector share_face_ = BoolVector(),
100 BoolVector wrap_ = BoolVector(),
101 CoordinateVector ghosts_ = CoordinateVector(),
102 DivisionsVector divisions_ = DivisionsVector()):
103 dim(dim_), domain(domain_), nblocks(nblocks_),
104 share_face(share_face_),
105 wrap(wrap_), ghosts(ghosts_), divisions(divisions_)
107 if ((
int) share_face.size() < dim) share_face.resize(dim);
108 if ((
int) wrap.size() < dim) wrap.resize(dim);
109 if ((
int) ghosts.size() < dim) ghosts.resize(dim);
110 if ((
int) divisions.size() < dim) divisions.resize(dim);
112 fill_divisions(divisions);
116 void decompose(
int rank,
const Assigner& assigner,
const Creator& create);
118 void decompose(
int rank,
const Assigner& assigner,
Master& master,
const Updater& update);
120 void decompose(
int rank,
const Assigner& assigner,
Master& master);
123 template<
class Po
int>
124 int lowest_gid(
const Point& p)
const;
126 void gid_to_coords(
int gid, DivisionsVector& coords)
const { gid_to_coords(gid, coords, divisions); }
127 int coords_to_gid(
const DivisionsVector& coords)
const {
return coords_to_gid(coords, divisions); }
128 void fill_divisions(std::vector<int>& divisions)
const;
130 void fill_bounds(Bounds& bounds,
const DivisionsVector& coords,
bool add_ghosts =
false)
const;
131 void fill_bounds(Bounds& bounds,
int gid,
bool add_ghosts =
false)
const;
133 static bool all(
const std::vector<int>& v,
int x);
134 static void gid_to_coords(
int gid, DivisionsVector& coords,
const DivisionsVector& divisions);
135 static int coords_to_gid(
const DivisionsVector& coords,
const DivisionsVector& divisions);
137 static void factor(std::vector<unsigned>& factors,
int n);
140 template<
class Po
int>
141 void point_to_gids(std::vector<int>& gids,
const Point& p)
const;
144 template<
class Po
int>
147 template<
class Po
int>
148 int num_gids(
const Point& p)
const;
150 template<
class Po
int>
151 void top_bottom(
int& top,
int& bottom,
const Point& p,
int axis)
const;
157 BoolVector share_face;
159 CoordinateVector ghosts;
160 DivisionsVector divisions;
180 template<
class Bounds>
185 const typename RegularDecomposer<Bounds>::Creator& create,
186 typename RegularDecomposer<Bounds>::BoolVector share_face =
typename RegularDecomposer<Bounds>::BoolVector(),
187 typename RegularDecomposer<Bounds>::BoolVector wrap =
typename RegularDecomposer<Bounds>::BoolVector(),
188 typename RegularDecomposer<Bounds>::CoordinateVector ghosts =
typename RegularDecomposer<Bounds>::CoordinateVector(),
189 typename RegularDecomposer<Bounds>::DivisionsVector divs =
typename RegularDecomposer<Bounds>::DivisionsVector())
210 template<
class Bounds>
216 typename RegularDecomposer<Bounds>::BoolVector share_face =
typename RegularDecomposer<Bounds>::BoolVector(),
217 typename RegularDecomposer<Bounds>::BoolVector wrap =
typename RegularDecomposer<Bounds>::BoolVector(),
218 typename RegularDecomposer<Bounds>::CoordinateVector ghosts =
typename RegularDecomposer<Bounds>::CoordinateVector(),
219 typename RegularDecomposer<Bounds>::DivisionsVector divs =
typename RegularDecomposer<Bounds>::DivisionsVector())
238 std::vector<int> local_gids;
241 for (
size_t i = 0; i < local_gids.size(); ++i)
242 master.
add(local_gids[i], master.create(),
new diy::Link);
254 template<
class Bounds>
260 const typename RegularDecomposer<Bounds>::Updater& update,
261 typename RegularDecomposer<Bounds>::BoolVector share_face =
262 typename RegularDecomposer<Bounds>::BoolVector(),
263 typename RegularDecomposer<Bounds>::BoolVector wrap =
264 typename RegularDecomposer<Bounds>::BoolVector(),
265 typename RegularDecomposer<Bounds>::CoordinateVector ghosts =
266 typename RegularDecomposer<Bounds>::CoordinateVector(),
267 typename RegularDecomposer<Bounds>::DivisionsVector divs =
268 typename RegularDecomposer<Bounds>::DivisionsVector())
271 decompose(rank, assigner, master, update);
279 template<
class Bounds>
282 decompose(
int rank,
const Assigner& assigner, Master& master)
284 decompose(rank, assigner, [&master](
int gid,
const Bounds& core,
const Bounds& bounds,
const Bounds& domain,
const Link& link)
286 void* b = master.create();
287 Link* l =
new Link(link);
288 master.add(gid, b, l);
292 template<
class Bounds>
295 decompose(
int rank,
const Assigner& assigner,
const Creator& create)
297 std::vector<int> gids;
298 assigner.local_gids(rank, gids);
299 for (
int i = 0; i < (int)gids.size(); ++i)
303 DivisionsVector coords;
304 gid_to_coords(gid, coords);
307 fill_bounds(core, coords);
308 fill_bounds(bounds, coords,
true);
311 Link link(dim, core, bounds);
312 std::vector<int> offsets(dim, -1);
314 while (!all(offsets, 1))
318 for (i = 0; i < dim; ++i)
325 if (all(offsets, 0))
continue;
327 DivisionsVector nhbr_coords(dim);
328 Direction dir, wrap_dir;
329 bool inbounds =
true;
330 for (
int i = 0; i < dim; ++i)
332 nhbr_coords[i] = coords[i] + offsets[i];
335 if (nhbr_coords[i] < 0)
339 nhbr_coords[i] = divisions[i] - 1;
346 if (nhbr_coords[i] >= divisions[i])
358 if (offsets[i] == -1 || offsets[i] == 1)
361 if (!inbounds)
continue;
363 int nhbr_gid = coords_to_gid(nhbr_coords);
364 BlockID bid; bid.gid = nhbr_gid; bid.proc = assigner.rank(nhbr_gid);
365 link.add_neighbor(bid);
368 fill_bounds(nhbr_bounds, nhbr_coords);
369 link.add_bounds(nhbr_bounds);
371 link.add_direction(dir);
372 link.add_wrap(wrap_dir);
375 create(gid, core, bounds, domain, link);
380 template<
class Bounds>
383 decompose(
int rank,
const Assigner& assigner, Master& master,
const Updater& update)
385 decompose(rank, assigner, [&master,&update](
int gid,
const Bounds& core,
const Bounds& bounds,
const Bounds& domain,
const Link& link)
387 int lid = master.lid(gid);
388 Link* l =
new Link(link);
389 master.replace_link(lid, l);
390 update(gid, lid, core, bounds, domain, *l);
394 template<
class Bounds>
397 all(
const std::vector<int>& v,
int x)
399 for (
unsigned i = 0; i < v.size(); ++i)
405 template<
class Bounds>
408 gid_to_coords(
int gid, DivisionsVector& coords,
const DivisionsVector& divisions)
410 int dim = divisions.size();
411 for (
int i = 0; i < dim; ++i)
413 coords.push_back(gid % divisions[i]);
418 template<
class Bounds>
421 coords_to_gid(
const DivisionsVector& coords,
const DivisionsVector& divisions)
424 for (
int i = coords.size() - 1; i >= 0; --i)
434 template<
class Bounds>
438 const DivisionsVector& coords,
442 for (
int i = 0; i < dim; ++i)
444 bounds.min[i] = detail::BoundsHelper<Bounds>::from(coords[i], divisions[i], domain.min[i], domain.max[i], share_face[i]);
445 bounds.max[i] = detail::BoundsHelper<Bounds>::to (coords[i], divisions[i], domain.min[i], domain.max[i], share_face[i]);
448 for (
int i = dim; i < DIY_MAX_DIM; ++i)
457 for (
int i = 0; i < dim; ++i)
461 bounds.min[i] -= ghosts[i];
462 bounds.max[i] += ghosts[i];
465 bounds.min[i] = std::max(domain.min[i], bounds.min[i] - ghosts[i]);
466 bounds.max[i] = std::min(domain.max[i], bounds.max[i] + ghosts[i]);
473 template<
class Bounds>
481 DivisionsVector coords;
482 gid_to_coords(gid, coords);
484 fill_bounds(bounds, coords,
true);
486 fill_bounds(bounds, coords);
489 namespace diy {
namespace detail {
491 template<
class Coordinate>
501 bool operator<(Div rhs)
const
504 if (b_size == rhs.b_size)
507 return(dim < rhs.dim);
510 return(b_size > rhs.b_size);
515 template<
class Bounds>
521 int prod = 1;
int c = 0;
522 for (
int i = 0; i < dim; ++i)
523 if (divisions[i] != 0)
525 prod *= divisions[i];
529 if (nblocks % prod != 0)
530 throw std::runtime_error(
"Total number of blocks cannot be factored into provided divs");
532 if (c == (
int) divisions.size())
537 std::vector<unsigned> factors;
538 factor(factors, nblocks/prod);
541 std::vector< Div<Coordinate> > missing_divs;
544 for (
int i = 0; i < dim; i++)
546 if (divisions[i] == 0)
551 div.b_size = domain.max[i] - domain.min[i];
552 missing_divs.push_back(div);
558 for (
int i = factors.size() - 1; i >= 0; --i)
565 std::sort(missing_divs.begin(), missing_divs.end());
569 detail::BoundsHelper<Bounds>::from(0,
570 missing_divs[0].nb * factors[i],
571 domain.min[missing_divs[0].dim],
572 domain.max[missing_divs[0].dim],
573 share_face[missing_divs[0].dim]);
575 detail::BoundsHelper<Bounds>::to(0,
576 missing_divs[0].nb * factors[i],
577 domain.min[missing_divs[0].dim],
578 domain.max[missing_divs[0].dim],
579 share_face[missing_divs[0].dim]);
582 missing_divs[0].nb *= factors[i];
583 missing_divs[0].b_size = max - min;
587 std::ostringstream oss;
588 oss <<
"Unable to decompose domain into " << nblocks <<
" blocks: " << min <<
" " << max;
589 throw std::runtime_error(oss.str());
594 for (
size_t i = 0; i < missing_divs.size(); i++)
595 divisions[missing_divs[i].dim] = missing_divs[i].nb;
598 template<
class Bounds>
601 factor(std::vector<unsigned>& factors,
int n)
604 for (
int i = 2; i <= n; ++i)
608 factors.push_back(i);
618 template<
class Bounds>
619 template<
class Po
int>
624 std::vector< std::pair<int, int> > ranges(dim);
625 for (
int i = 0; i < dim; ++i)
626 top_bottom(ranges[i].second, ranges[i].first, p, i);
629 DivisionsVector coords(dim), location(dim);
630 while(location.back() < ranges.back().second - ranges.back().first)
632 for (
int i = 0; i < dim; ++i)
633 coords[i] = ranges[i].first + location[i];
634 gids.push_back(coords_to_gid(coords, divisions));
638 while (i < dim-1 && location[i] == ranges[i].second - ranges[i].first)
647 template<
class Bounds>
648 template<
class Po
int>
654 for (
int axis = dim - 1; axis >= 0; --axis)
656 int bottom = detail::BoundsHelper<Bounds>::lower(p[axis], divisions[axis], domain.min[axis], domain.max[axis], share_face[axis]);
657 bottom = std::max(0, bottom);
660 gid *= divisions[axis];
667 template<
class Bounds>
668 template<
class Po
int>
674 for (
int i = 0; i < dim; ++i)
677 top_bottom(top, bottom, p, i);
683 template<
class Bounds>
684 template<
class Po
int>
687 top_bottom(
int& top,
int& bottom,
const Point& p,
int axis)
const
689 Coordinate l = p[axis] - ghosts[axis];
690 Coordinate r = p[axis] + ghosts[axis];
692 top = detail::BoundsHelper<Bounds>::upper(r, divisions[axis], domain.min[axis], domain.max[axis], share_face[axis]);
693 bottom = detail::BoundsHelper<Bounds>::lower(l, divisions[axis], domain.min[axis], domain.max[axis], share_face[axis]);
697 bottom = std::max(0, bottom);
698 top = std::min(divisions[axis], top);
703 template<
class Bounds>
704 template<
class Po
int>
710 std::vector<int> gids;
711 point_to_gids(gids, p);
int point_to_gid(const Point &p) const
returns gid of a block that contains the point; ignores ghosts
Definition: decomposition.hpp:651
int nblocks() const
returns the total number of global blocks
Definition: assigner.hpp:26
Decomposes a regular (discrete or continuous) domain into even blocks; creates Links with Bounds alon...
Definition: decomposition.hpp:75
void decompose(int dim, int rank, const Bounds &domain, const Assigner &assigner, Master &master, const typename RegularDecomposer< Bounds >::Updater &update, typename RegularDecomposer< Bounds >::BoolVector share_face=typename RegularDecomposer< Bounds >::BoolVector(), typename RegularDecomposer< Bounds >::BoolVector wrap=typename RegularDecomposer< Bounds >::BoolVector(), typename RegularDecomposer< Bounds >::CoordinateVector ghosts=typename RegularDecomposer< Bounds >::CoordinateVector(), typename RegularDecomposer< Bounds >::DivisionsVector divs=typename RegularDecomposer< Bounds >::DivisionsVector())
Add a decomposition (modify links) of an existing set of blocks that were added to the master previou...
Definition: decomposition.hpp:255
Definition: assigner.hpp:11
void decompose(int dim, int rank, const Bounds &domain, const Assigner &assigner, const typename RegularDecomposer< Bounds >::Creator &create, typename RegularDecomposer< Bounds >::BoolVector share_face=typename RegularDecomposer< Bounds >::BoolVector(), typename RegularDecomposer< Bounds >::BoolVector wrap=typename RegularDecomposer< Bounds >::BoolVector(), typename RegularDecomposer< Bounds >::CoordinateVector ghosts=typename RegularDecomposer< Bounds >::CoordinateVector(), typename RegularDecomposer< Bounds >::DivisionsVector divs=typename RegularDecomposer< Bounds >::DivisionsVector())
Decomposes the domain into a prescribed pattern of blocks.
Definition: decomposition.hpp:181
int add(int gid, void *b, Link *l)
add a block
Definition: master.hpp:658
Definition: master.hpp:35
virtual void local_gids(int rank, std::vector< int > &gids) const =0
gets the local gids for a given process rank
RegularDecomposer(int dim_, const Bounds &domain_, int nblocks_, BoolVector share_face_=BoolVector(), BoolVector wrap_=BoolVector(), CoordinateVector ghosts_=CoordinateVector(), DivisionsVector divisions_=DivisionsVector())
Definition: decomposition.hpp:96
void fill_bounds(Bounds &bounds, const DivisionsVector &coords, bool add_ghosts=false) const
Gets the bounds, with or without ghosts, for a block specified by its block coordinates.
Definition: decomposition.hpp:437
void sort(Master &master, const Assigner &assigner, std::vector< T > Block::*values, std::vector< T > Block::*samples, size_t num_samples, const Cmp &cmp, int k=2, bool samples_only=false)
sample sort values of each block, store the boundaries between blocks in samples
Definition: algorithms.hpp:25