1 #ifndef UTOPIA_CORE_GRIDS_SQUARE_HH
2 #define UTOPIA_CORE_GRIDS_SQUARE_HH
70 if constexpr (
dim > 1) {
74 if (eff_res.min() != eff_res.max()) {
76 std::stringstream efr_ss;
79 throw std::invalid_argument(
"Given the extent of the physical "
80 "space and the specified resolution, a mapping with "
81 "exactly square cells could not be found! Either adjust "
82 "the physical space, the resolution of the grid, or "
83 "choose another grid. Effective resolution was:\n"
84 + efr_ss.str() +
", but should be the same in all "
97 return std::accumulate(this->_shape.begin(), this->_shape.end(),
98 1, std::multiplies<IndexType>());
126 static_assert(
dim <= 2,
"MultiIndex only implemented for 1D and 2D!");
128 if constexpr (
dim == 1) {
161 static_assert(
dim == 2,
162 "SquareGrid::vertices_of is only implemented for 2D!");
191 static_assert(
dim == 2,
192 "SquareGrid::cell_at only implemented for 2D!");
195 using midx_et =
typename MultiIndex::elem_type;
211 midx = {
static_cast<midx_et
>(ridx[0]),
212 static_cast<midx_et
>(ridx[1])};
216 if (not this->
_space->contains(pos)) {
217 throw std::invalid_argument(
"The given position is outside "
218 "the non-periodic space associated with this grid!");
225 midx = {
static_cast<midx_et
>(ridx[0]),
226 static_cast<midx_et
>(ridx[1])};
229 if (midx[0] ==
_shape[0]) {
232 if (midx[1] ==
_shape[1]) {
240 return midx[0] + (midx[1] *
_shape[0]);
259 static_assert(
dim <= 2,
260 "SquareGrid::boundary_cells only implemented for 1D and 2D!");
265 std::set<IndexType> bc_ids;
268 if constexpr (
dim == 1) {
269 if (select !=
"all" and select !=
"left" and select !=
"right") {
270 throw std::invalid_argument(
"Invalid value for argument "
271 "`select` in call to method SquareGrid::boundary_cells! "
272 "Available arguments (for currently selected "
273 "dimensionality) are: "
274 "'all', 'left', 'right'. Given value: '" + select +
"'");
282 if (select ==
"all" or select ==
"left") {
287 if (select ==
"all" or select ==
"right") {
288 bc_ids.emplace_hint(bc_ids.end(),
_shape[0] - 1);
291 else if constexpr (
dim == 2) {
293 and select !=
"left" and select !=
"right"
294 and select !=
"bottom" and select !=
"top")
296 throw std::invalid_argument(
"Invalid value for argument "
297 "`select` in call to method SquareGrid::boundary_cells! "
298 "Available arguments (for currently selected "
299 "dimensionality) are: "
300 "'all', 'left', 'right', 'bottom', 'top'. Given value: '"
315 auto hint = bc_ids.begin();
318 if (select ==
"all" or select ==
"bottom") {
321 bc_ids.emplace_hint(hint,
id);
327 if (select ==
"left") {
330 bc_ids.emplace_hint(hint, row *
_shape[0]);
336 if (select ==
"right") {
338 const auto offset =
_shape[0] - 1;
341 bc_ids.emplace_hint(hint, offset + row *
_shape[0]);
347 if (select ==
"all") {
349 const auto offset =
_shape[0] - 1;
353 bc_ids.emplace_hint(hint, row *
_shape[0]);
356 bc_ids.emplace_hint(bc_ids.end(),
357 offset + row *
_shape[0]);
364 if (select ==
"all" or select ==
"top") {
369 bc_ids.emplace_hint(hint,
id);
417 +
"' available for rectangular grid discretization!");
443 constexpr
bool check_shape =
true;
444 const auto distance = get_nb_param_distance<check_shape>(
nb_params);
468 static_assert((
dim >= 1 and
dim <= 2),
469 "VonNeumann neighborhood is implemented only for 1D or 2D "
481 for (
DistType dist=1; dist <= distance; ++dist) {
482 add_low_val_neighbor_in_<0, true>(root_id,
485 add_high_val_neighbor_in_<0, true>(root_id,
491 if constexpr (
dim >= 2) {
498 const auto nb_size = neighbor_ids.size();
504 dist <= distance - 1 - i/2 + (i%2)/2;
508 add_low_val_neighbor_in_<1, true>(neighbor_ids[i],
513 add_high_val_neighbor_in_<1, true>(neighbor_ids[i],
520 for (
DistType dist=1; dist <= distance; ++dist) {
521 add_low_val_neighbor_in_<1, true>(root_id,
524 add_high_val_neighbor_in_<1,true>(root_id,
537 static_assert(((
dim == 1) or (
dim == 2)),
538 "VonNeumann neighborhood is implemented only for 1D or 2D "
551 back_nb_ids.reserve(
nb_size / 2);
556 for (
DistType dist=1; dist <= distance; ++dist) {
557 add_low_val_neighbor_in_<0, false>(root_id,
560 add_high_val_neighbor_in_<0, false>(root_id,
566 if constexpr (
dim >= 2) {
573 const DistType front_nb_size = front_nb_ids.size();
575 for (
DistType i=0; i < front_nb_size; ++i) {
579 dist <= distance - (i + 1);
583 add_low_val_neighbor_in_<1, false>(front_nb_ids[i],
588 add_high_val_neighbor_in_<1,false>(front_nb_ids[i],
600 const DistType back_nb_size = back_nb_ids.size();
602 for (
DistType i=0; i<back_nb_size; ++i) {
606 dist <= distance - (i + 1);
609 add_low_val_neighbor_in_<1, false>(back_nb_ids[i],
613 add_high_val_neighbor_in_<1, false>(back_nb_ids[i],
620 for (
DistType dist=1; dist <= distance; ++dist) {
621 add_low_val_neighbor_in_<1, false>(root_id,
625 add_high_val_neighbor_in_<1, false>(root_id,
632 front_nb_ids.insert(front_nb_ids.end(),
633 back_nb_ids.begin(), back_nb_ids.end());
646 static_assert((
dim >= 1 and
dim <= 2),
647 "VonNeumann neighborhood is implemented only for 1D or 2D space!");
654 neighbor_ids.reserve(2 *
dim);
658 add_neighbors_in_<0, true>(root_id, neighbor_ids);
660 if constexpr (
dim >= 2) {
661 add_neighbors_in_<1, true>(root_id, neighbor_ids);
673 static_assert(((
dim == 1) or (
dim == 2)),
674 "VonNeumann neighborhood is only implemented in 1 or 2 dimensions "
682 neighbor_ids.reserve(2 *
dim);
686 add_neighbors_in_<0, false>(root_id, neighbor_ids);
688 if constexpr (
dim >= 2) {
689 add_neighbors_in_<1, false>(root_id, neighbor_ids);
715 constexpr
bool check_shape =
true;
716 const auto distance = get_nb_param_distance<check_shape>(
nb_params);
740 static_assert(
dim == 2,
741 "Moore neighborhood is only available in 2D!");
750 for (
DistType dist=1; dist <= distance; ++dist) {
751 add_low_val_neighbor_in_<0, true>(root_id, dist,
753 add_high_val_neighbor_in_<0, true>(root_id, dist,
758 for (
const auto& nb : neighbor_ids) {
759 for (
DistType dist=1; dist <= distance; ++dist) {
760 add_low_val_neighbor_in_<1, true>(nb, dist,
762 add_high_val_neighbor_in_<1, true>(nb, dist,
768 for (
DistType dist=1; dist <= distance; ++dist) {
769 add_low_val_neighbor_in_<1, true>(root_id, dist,
771 add_high_val_neighbor_in_<1, true>(root_id, dist,
780 static_assert(
dim == 2,
781 "Moore neighborhood is only available in 2D!");
790 for (
DistType dist=1; dist <= distance; ++dist) {
791 add_low_val_neighbor_in_<0, false>(root_id, dist,
793 add_high_val_neighbor_in_<0, false>(root_id, dist,
798 for (
const auto& nb : neighbor_ids) {
799 for (
DistType dist=1; dist <= distance; ++dist) {
800 add_low_val_neighbor_in_<1, false>(nb, dist,
802 add_high_val_neighbor_in_<1, false>(nb, dist, neighbor_ids);
807 for (
DistType dist=1; dist <= distance; ++dist) {
808 add_low_val_neighbor_in_<1, false>(root_id, dist,
810 add_high_val_neighbor_in_<1, false>(root_id, dist,
823 static_assert(
dim == 2,
"Moore neighborhood is only available in 2D!");
827 neighbor_ids.reserve(8);
830 add_neighbors_in_<1, true>(root_id, neighbor_ids);
834 add_neighbors_in_<0, true>(neighbor_ids[0], neighbor_ids);
835 add_neighbors_in_<0, true>(neighbor_ids[1], neighbor_ids);
838 add_neighbors_in_<0, true>(root_id, neighbor_ids);
847 static_assert(
dim == 2,
"Moore neighborhood is only available in 2D!");
851 neighbor_ids.reserve(8);
854 add_neighbors_in_<1, false>(root_id, neighbor_ids);
859 if (neighbor_ids.size() == 2) {
861 add_neighbors_in_<0, false>(neighbor_ids[0], neighbor_ids);
862 add_neighbors_in_<0, false>(neighbor_ids[1], neighbor_ids);
864 else if (neighbor_ids.size() == 1) {
866 add_neighbors_in_<0, false>(neighbor_ids[0], neighbor_ids);
871 add_neighbors_in_<0, false>(root_id, neighbor_ids);
890 template<DimType axis>
892 if constexpr (axis == 0) {
919 template<DimType axis,
bool periodic>
924 static_assert(
dim <= 2,
925 "Unsupported dimensionality of underlying space! Need be 1 or 2.");
926 static_assert(axis <
dim);
930 const auto nrm_id = ( (root_id % id_shift<axis+1>())
936 if constexpr (periodic) {
937 neighbor_ids.push_back( root_id
939 + id_shift<axis+1>());
945 neighbor_ids.push_back(root_id - id_shift<axis>());
949 if (nrm_id ==
_shape[axis] - 1) {
950 if constexpr (periodic) {
951 neighbor_ids.push_back( root_id
953 - id_shift<axis+1>());
957 neighbor_ids.push_back(root_id + id_shift<axis>());
979 template<DimType axis,
bool periodic>
985 static_assert(
dim <= 2,
986 "Unsupported dimensionality of underlying space! Need be 1 or 2.");
987 static_assert(axis <
dim);
998 if ( (root_id % id_shift<axis+1>()) / id_shift<axis>()
1001 if constexpr (periodic) {
1002 neighbor_ids.push_back( root_id
1003 - distance * id_shift<axis>()
1004 + id_shift<axis+1>());
1008 neighbor_ids.push_back( root_id
1009 - distance * id_shift<axis>());
1031 template<DimType axis,
bool periodic>
1037 static_assert(
dim <= 2,
1038 "Unsupported dimensionality of underlying space! Need be 1 or 2.");
1039 static_assert(axis <
dim);
1042 if (distance == 0) {
1050 if ( (root_id % id_shift<axis+1>()) / id_shift<axis>()
1051 >=
_shape[axis] - distance)
1053 if constexpr (periodic) {
1054 neighbor_ids.push_back( root_id
1055 + distance * id_shift<axis>()
1056 - id_shift<axis+1>());
1060 neighbor_ids.push_back( root_id
1061 + distance * id_shift<axis>());
1101 if (distance <= 1) {
1102 return std::pow(2 + 1,
dim) - 1;
1105 return std::pow(2 * distance + 1,
dim) - 1;
1114 auto num_nbs_impl = [](
const unsigned short int d,
1120 return 2 * distance;
1125 while (distance > 0) {
1126 cnt += 2 * num_nbs_ref(d-1, distance, num_nbs_ref);
1134 return num_nbs_impl(this->dim, distance, num_nbs_impl);
1138 +
"' available for rectangular grid discretization!");
1158 template<
bool check_shape=false>
1160 const auto distance = get_as<DistType>(
"distance", params, 1);
1166 if constexpr (check_shape) {
1168 and (distance * 2 + 1 > this->
shape().min()))
1172 std::stringstream shape_ss;
1173 this->
shape().print(shape_ss,
"Grid Shape:");
1175 throw std::invalid_argument(
"The grid shape is too small to "
1176 "accomodate a neighborhood with 'distance' parameter set "
1177 "to " + get_as<std::string>(
"distance", params,
"1")
1178 +
" in a periodic space!\n" + shape_ss.str());
The base class for all grid discretizations used by the CellManager.
Definition: base.hh:99
const DistType _resolution
How many cells to place per length unit of space.
Definition: base.hh:127
bool is_periodic() const
Whether the space this grid maps to is periodic.
Definition: base.hh:304
const NBMode & nb_mode() const
Const reference to the currently selected neighborhood mode.
Definition: base.hh:198
const std::shared_ptr< Space > _space
The space that is to be discretized.
Definition: base.hh:120
const Config & nb_params() const
The neighborhood parameters of the currently selected neighborhood.
Definition: base.hh:203
NBFuncID< Self > _nb_empty
A neighborhood function for empty neighborhood.
Definition: base.hh:323
const std::shared_ptr< Space > & space() const
Const reference to the space this grid maps to.
Definition: base.hh:299
auto nb_size() const
Maximum size of the currently selected neighborhood.
Definition: base.hh:208
DataIO::Config Config
The configuration type.
Definition: base.hh:114
A grid discretization using square cells.
Definition: square.hh:31
GridStructure structure() const override
Structure of the grid.
Definition: square.hh:116
IndexType num_cells() const override
Number of square cells required to fill the physical space.
Definition: square.hh:96
const SpaceVec _cell_extent
The extent of each cell of this square discretization (same for all)
Definition: square.hh:55
IndexType cell_at(const SpaceVec &pos) const override
Return the ID of the cell covering the given point in physical space.
Definition: square.hh:190
std::set< IndexType > boundary_cells(std::string select="all") const override
Retrieve a set of cell indices that are at a specified boundary.
Definition: square.hh:257
NBFuncID< Base > get_nb_func(NBMode nb_mode, const Config &nb_params) override
Retrieve the neighborhood function depending on the mode and parameters.
Definition: square.hh:403
SpaceVec barycenter_of(const IndexType id) const override
Returns the barycenter of the cell with the given ID.
Definition: square.hh:140
MultiIndex shape() const override
Get shape of the square grid.
Definition: square.hh:111
NBFuncID< Base > get_nb_func_vonNeumann(const Config &nb_params)
Returns a standalone von-Neumann neighborhood function.
Definition: square.hh:441
SquareGrid(std::shared_ptr< Space > space, const Config &cfg)
Construct a rectangular grid discretization.
Definition: square.hh:64
void add_neighbors_in_(const IndexType root_id, IndexContainer &neighbor_ids) const
Add both direct neighbors to a container of indices.
Definition: square.hh:920
NBFuncID< Base > get_nb_func_Moore(const Config &nb_params)
Returns a standalone Moore neighborhood function.
Definition: square.hh:713
DistType get_nb_param_distance(const Config ¶ms) const
Extract the distance neighborhood parameter from the given config.
Definition: square.hh:1159
std::vector< SpaceVec > vertices_of(const IndexType id) const override
Returns the vertices of the cell with the given ID.
Definition: square.hh:160
NBFuncID< Base > _nb_Moore_nonperiodic
Moore neighbors for non-periodic 2D grid.
Definition: square.hh:844
NBFuncID< Base > _nb_Moore_periodic
Moore neighbors for periodic 2D grid.
Definition: square.hh:820
MultiIndex midx_of(const IndexType id) const override
Returns the multi-index of the cell with the given ID.
Definition: square.hh:125
SpaceVec extent_of(const IndexType) const override
Returns the extent of the cell with the given ID.
Definition: square.hh:149
SpaceVec effective_resolution() const override
The effective cell resolution into each physical space dimension.
Definition: square.hh:105
MultiIndexType< dim > MultiIndex
The type of multi-index like arrays, e.g. the grid shape.
Definition: square.hh:43
void add_high_val_neighbor_in_(const IndexType root_id, const DistType distance, IndexContainer &neighbor_ids) const
Add a neighbor on the high (ID) value side to an index container.
Definition: square.hh:1032
static constexpr DimType dim
The dimensionality of the space to be discretized (for easier access)
Definition: square.hh:37
typename Space::SpaceVec SpaceVec
The type of vectors that have a relation to physical space.
Definition: square.hh:40
MultiIndex determine_shape() const
Given the resolution, return the grid shape required to fill the space.
Definition: square.hh:388
NBFuncID< Base > _nb_vonNeumann_periodic
The Von-Neumann neighborhood for periodic grids.
Definition: square.hh:643
DistType expected_num_neighbors(const NBMode &nb_mode, const Config &nb_params) const override
Computes the expected number of neighbors for a neighborhood mode.
Definition: square.hh:1090
constexpr IndexType id_shift() const
Return the shift in cell indices necessary if moving along an axis.
Definition: square.hh:891
const MultiIndex _shape
The (multi-index) shape of the grid, resulting from resolution.
Definition: square.hh:52
NBFuncID< Base > _nb_vonNeumann_nonperiodic
The Von-Neumann neighborhood for non-periodic grids.
Definition: square.hh:670
void add_low_val_neighbor_in_(const IndexType root_id, const DistType distance, IndexContainer &neighbor_ids) const
Add a neighbor on the low (ID) value side to an index container.
Definition: square.hh:980
NBMode
Possible neighborhood types; availability depends on choice of grid.
Definition: base.hh:52
std::string nb_mode_to_string(const NBMode &nb_mode)
Given an NBMode enum value, return the corresponding string key.
Definition: base.hh:78
GridStructure
Available grid implementations.
Definition: base.hh:13
std::function< IndexContainer(const IndexType)> NBFuncID
Type of the neighborhood calculating function.
Definition: base.hh:92
@ vonNeumann
The vonNeumann neighborhood, i.e. only nearest neighbors.
@ Moore
The Moore neighborhood, i.e. nearest and next nearest neighbors.
@ empty
Every entity is utterly alone in the world.
@ square
A square lattice grid.
YAML::Node Config
Type of a variadic dictionary-like data structure used throughout Utopia.
Definition: types.hh:71
@ vertices
Iterate over vertices.
arma::Col< IndexType >::fixed< dim > MultiIndexType
Type for index type vectors that are associated with a physical space.
Definition: types.hh:53
std::vector< IndexType > IndexContainer
Type for container of indices.
Definition: types.hh:43
unsigned short DimType
Type for dimensions, i.e. very small unsigned integers.
Definition: types.hh:34
unsigned int DistType
Type for distancens, i.e. intermediately long unsigned integers.
Definition: types.hh:37
std::size_t IndexType
Type for indices, i.e. values used for container indexing, agent IDs, ...
Definition: types.hh:40
SpaceVecType< dim > SpaceVec
The type for vectors relating to physical space.
Definition: space.hh:33
static constexpr std::size_t dim
The dimensionality of the space.
Definition: space.hh:30