Utopia 2
Framework for studying models of complex & adaptive systems.
Loading...
Searching...
No Matches
hexagonal.hh
Go to the documentation of this file.
1#ifndef UTOPIA_CORE_GRIDS_HEXAGONAL_HH
2#define UTOPIA_CORE_GRIDS_HEXAGONAL_HH
3
4#include "base.hh"
5
6namespace Utopia {
13
47template<class Space>
49 : public Grid<Space>
50{
51public:
54
56 static constexpr DimType dim = Space::dim;
57
59 using SpaceVec = typename Space::SpaceVec;
60
63
66
67
68private:
69 // -- HexagonalGrid-specific members --------------------------------------
72
74
77
78public:
79 // -- Constructors --------------------------------------------------------
81
84 HexagonalGrid (std::shared_ptr<Space> space, const Config& cfg)
85 :
86 Base(space, cfg),
89 {
90 // Make sure the cells really are hexagonal
91 static_assert(dim == 2, "Hexagonal grid is only implemented for 2D "
92 "space!");
93
95
96 // check that the cell extent corresponds to that of pointy-topped
97 // hexagonal cells
98 // NOTE the test only requires the aspect ratio is precise to 2% for
99 // easy user experience. The hexagonal grid requires a space
100 // with an aspect ratio involving a sqrt(3)
101 if ( fabs(_cell_extent[0] / _cell_extent[1] - sqrt(3.) / 2.)
102 > get_as<double>("aspect_ratio_tolerance", cfg, 0.02))
103 {
104 SpaceVec required_space = SpaceVec({1., 0.75 * 2. / sqrt(3.)});
105 required_space[0] = this->_space->extent[0];
106 required_space[1] = _shape[1] * _cell_extent[0] * 1.5 /sqrt(3.);
107 std::stringstream required_space_ss;
109
110 throw std::invalid_argument(fmt::format(
111 "Given the extent of the physical space and the specified "
112 "resolution, a mapping with hexagonal cells could not be "
113 "found! Either adjust the the extent of physical space or the "
114 "resolution of the grid. Alternatively increase the tolerance "
115 "to distorted hexagons or choose another grid. \n"
116 "The required aspect ratio of sqrt(3) / 2 is violated by {} "
117 "(> `aspect_ratio_tolerance` = {})! \n"
118 "With the given resolution, set the space extent to : \n"
119 "{} or increase the resolution.",
120 fabs(_cell_extent[0] / _cell_extent[1] - sqrt(3.) / 2.),
121 get_as<double>("aspect_ratio_tolerance", cfg, 0.02),
123 ));
124
125 }
126 }
127
128
129 // -- Implementations of virtual base class functions ---------------------
130 // .. Number of cells & shape .............................................
131
133
135 IndexType num_cells() const override {
136 return _shape[0] * _shape[1];
137 }
138
141 return SpaceVec({static_cast<double>(_shape[0]), 0.75*_shape[1]})
142 / this->_space->extent;
143 }
144
146 MultiIndex shape() const override {
147 return _shape;
148 }
149
151 GridStructure structure() const override {
153 }
154
155
156 // .. Position-related methods ............................................
158
160 MultiIndex midx_of(const IndexType id) const override {
161 return MultiIndex({id % _shape[0], id / _shape[0]});
162 }
163
165
167 SpaceVec barycenter_of(const IndexType id) const override {
168 MultiIndex mid = midx_of(id);
169 if (mid[1] % 2 == 0) {
170 // even row
171 return (mid % SpaceVec({1., 0.75}) + SpaceVec({1., 0.5}))
172 % _cell_extent;
173 }
174 else {
175 // odd row
176 return ( (mid % SpaceVec({1, 0.75}) + SpaceVec({0.5, 0.5}))
177 % _cell_extent);
178 }
179 }
180
182
186 SpaceVec extent_of(const IndexType) const override {
187 return _cell_extent;
188 }
189
191
197 std::vector<SpaceVec> vertices_of(const IndexType id) const override {
198 std::vector<SpaceVec> vertices{};
199 vertices.reserve(6);
200
201 const SpaceVec center = barycenter_of(id);
202
203 vertices.push_back(center + SpaceVec({-0.5, -0.25}) % _cell_extent);
204 vertices.push_back(center + SpaceVec({ 0. , -0.5 }) % _cell_extent);
205 vertices.push_back(center + SpaceVec({ 0.5, -0.25}) % _cell_extent);
206 vertices.push_back(center + SpaceVec({ 0.5, 0.25}) % _cell_extent);
207 vertices.push_back(center + SpaceVec({ 0. , 0.5 }) % _cell_extent);
208 vertices.push_back(center + SpaceVec({-0.5, 0.25}) % _cell_extent);
209
210 return vertices;
211 }
212
214
248 IndexType cell_at(const SpaceVec& pos) const override {
249 SpaceVec ridx = pos;
250 // check position
251 if (this->is_periodic()) {
252 ridx = this->_space->map_into_space(pos);
253 }
254 else if (not this->_space->contains(pos)) {
255 throw std::invalid_argument("The given position is outside "
256 "the non-periodic space associated with this grid!");
257 }
258
259 // relative and centered in cell 0
260 ridx = ridx / _cell_extent - SpaceVec({1., 0.5});
261
262 arma::Col<int>::fixed<dim> midx = {
263 static_cast<int>(std::round(ridx[0] + 2. / 3. * ridx[1])),
264 static_cast<int>(std::round(4. / 3. * ridx[1]))
265 };
266
267 // correct for offset
268 midx[0] -= std::floor(midx[1] / 2.);
269
270 if (not this->is_periodic()) {
271 // remap not represented space to first cell in this row
272 // NOTE this distorts the cells, but the rectangular space is
273 // correctly represented
274 if (midx[0] == -1) {
275 midx[0]++;
276 }
277 if (midx[1] == -1) {
278 midx[1]++;
279 }
280
281 // Associate points on high-value boundaries with boundary cells
282 if (midx[0] == static_cast<int>(_shape[0])) {
283 midx[0]--;
284 }
285 }
286 else {
287 midx[0] = (midx[0] + _shape[0]) % _shape[0];
288 midx[1] = (midx[1] + _shape[1]) % _shape[1];
289 }
290
291 // From the multi index, calculate the corresponding ID
292 return static_cast<IndexType>(midx[0] + (midx[1] * _shape[0]));
293 // Equivalent to:
294 // midx[0] * id_shift<0>()
295 // + midx[1] * id_shift<1>()
296 }
297
299
307 std::set<IndexType> boundary_cells(std::string select="all") const override
308 {
309 if ( select != "all"
310 and select != "left" and select != "right"
311 and select != "bottom" and select != "top")
312 {
313 throw std::invalid_argument("Invalid value for argument "
314 "`select` in call to method SquareGrid::boundary_cells! "
315 "Available arguments (for currently selected "
316 "dimensionality) are: "
317 "'all', 'left', 'right', 'bottom', 'top'. Given value: '"
318 + select + "'");
319 }
320
321 // The target set all IDs are to be emplaced in
322 std::set<IndexType> bc_ids;
323
324 // For periodic space, this is easy:
325 if (this->is_periodic()) {
326 return {};
327 }
328
329 // NOTE It is important to use the hinting features of std::set
330 // here, which allow to run the following in amortized
331 // constant time instead of logarithmic with set size.
332 // Below, it always makes sense to hint at inserting right
333 // before the end.
334 // Hint for the first element needs to be the beginning
335 auto hint = bc_ids.begin();
336
337 // Bottom boundary (lowest IDs)
338 if (select == "all" or select == "bottom") {
339 // 0, ..., _shape[0] - 1
340 for (DistType id = 0; id < _shape[0]; id++) {
341 bc_ids.emplace_hint(hint, id);
342 hint = bc_ids.end();
343 }
344 }
345
346 // Left boundary
347 if (select == "left") {
348 // First IDs in _shape[1] rows: 0, _shape[0], 2*_shape[0], ...
349 for (DistType row = 0; row < _shape[1]; row++) {
350 bc_ids.emplace_hint(hint, row * _shape[0]);
351 hint = bc_ids.end();
352 }
353 }
354
355 // Right boundary
356 if (select == "right") {
357 // Last IDs in _shape[1] rows
358 const auto offset = _shape[0] - 1;
359
360 for (DistType row = 0; row < _shape[1]; row++) {
361 bc_ids.emplace_hint(hint, offset + row * _shape[0]);
362 hint = bc_ids.end();
363 }
364 }
365
366 // Left AND right (only for 'all' case, allows better hints)
367 if (select == "all") {
368 // First and last IDs in _shape[1] rows
369 const auto offset = _shape[0] - 1;
370
371 for (DistType row = 0; row < _shape[1]; row++) {
372 // Left boundary cell
373 bc_ids.emplace_hint(hint, row * _shape[0]);
374
375 // Right boundary cell (higher than left cell ID)
376 bc_ids.emplace_hint(bc_ids.end(),
377 offset + row * _shape[0]);
378
379 hint = bc_ids.end();
380 }
381 }
382
383 // Top boundary (highest IDs)
384 if (select == "all" or select == "top") {
385 // _shape[0] * (_shape[1]-1), ..., _shape[0] * _shape[1] - 1
386 for (DistType id = _shape[0] * (_shape[1]-1);
387 id < _shape[0] * _shape[1]; id++)
388 {
389 bc_ids.emplace_hint(hint, id);
390 hint = bc_ids.end();
391 }
392 }
393
394 return bc_ids;
395 }
396
397
398private:
399 // -- Helper functions ----------------------------------------------------
401
415
416 // obtain the sidelength of a unit area hexagon
417 // A = 3^1.5 / 2 s^2
418 double s = sqrt(2. / (3 * sqrt(3)));
419 double width = sqrt(3) * s;
420 double height = 2 * s;
421
422 shape[0] = std::round( this->_space->extent[0] / width
423 * this->_resolution);
424 shape[1] = std::round( this->_space->extent[1] / (0.75 * height)
425 * this->_resolution);
426
427 // in non periodic space pair number of rows required
428 if (this->is_periodic()) {
429 shape[1] = shape[1] - shape[1] % 2;
430 }
431
432 return shape;
433 }
434
435
436protected:
437 // -- Neighborhood interface ----------------------------------------------
440 const Config& nb_params) override
441 {
442 if (nb_mode == NBMode::empty) {
443 return this->_nb_empty;
444 }
445 else if (nb_mode == NBMode::hexagonal) {
447 }
448 else {
449 throw std::invalid_argument("No '" + nb_mode_to_string(nb_mode)
450 + "' neighborhood available for HexagonalGrid! "
451 "Available modes: empty, hexagonal.");
452 }
453 }
454
457 const Config&) const override
458 {
459 if (nb_mode == NBMode::empty) {
460 return 0;
461 }
462 else if (nb_mode == NBMode::hexagonal) {
463 return 6;
464 }
465 else {
466 throw std::invalid_argument("No '" + nb_mode_to_string(nb_mode)
467 + "' neighborhood available for HexagonalGrid! "
468 "Available modes: empty, hexagonal.");
469 }
470 }
471
472
473 // .. Neighborhood implementations ........................................
474 // NOTE With C++20, the below lambdas would allow template arguments
475
476 // .. hexagonal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
477
479
493 // Extract the optional distance parameter
494 constexpr bool check_shape = true;
495 const auto distance = get_nb_param_distance<check_shape>(nb_params);
496
497 // For distance 1, use the specialized functions which are defined as
498 // class members (to don't bloat this method even more). Those
499 // functions do not require any calculation or capture that goes beyond
500 // the capture of ``this``.
501 if (distance <= 1) {
502 if (this->is_periodic()) {
504 }
505 else {
507 }
508 }
509 // else: distance is > 1. Depending on periodicity of the grid, define
510 // the relevant lambda and let it capture as many values as possible in
511 // order to avoid recomputation.
512
513 throw std::invalid_argument(fmt::format(
514 "Hexagonal neighborhood is not implemented for a "
515 "distance larger than 1. Requested distance was {}.",
516 distance
517 ));
518 }
519
520
523 [this](const IndexType root_id)
524 {
525 // Instantiate container in which to store the neighboring cell IDs
527
528 // The number of neighbors is known; pre-allocating space brings a
529 // speed improvement of about factor 2.
530 neighbor_ids.reserve(3 * dim);
531
532 // Depending on the number of dimensions, add the IDs of neighboring
533 // cells in those dimensions
537
538 // Return the container of cell indices
539 return neighbor_ids;
540 };
541
542
545 [this](const IndexType root_id)
546 {
547 // Instantiate container in which to store the neighboring cell IDs
549
550 // The number of neighbors is known; pre-allocating space brings a
551 // speed improvement of about factor 2
552 neighbor_ids.reserve(2 * dim);
553
554 // Depending on the number of dimensions, add the IDs of neighboring
555 // cells in those dimensions
559
560 // Return the container of cell indices
561 return neighbor_ids;
562 };
563
564
565 // .. Neighborhood helper functions .......................................
566
568
584 template<DimType axis, bool periodic>
587 {
588 // Assure the number of dimensions is supported
589 static_assert(axis < 3);
590
591 // left and right
592 if constexpr (axis == 0) {
593 // Compute a normalized id
594 const IndexType nrm_id = root_id % _shape[0];
595
596 // Check if at low value boundary
597 if (nrm_id == 0) {
598 // left most column
599 if constexpr (periodic) {
600 neighbor_ids.push_back(root_id - 1 + _shape[0]);
601 }
602 // else: not periodic; nothing to add here
603 }
604 else {
605 // Not at boundary; no need for the correction term
606 neighbor_ids.push_back(root_id - 1);
607 }
608
609 // Check if at high value boundary
610 if (nrm_id == _shape[0] - 1) {
611 // right most column
612 if constexpr (periodic) {
613 neighbor_ids.push_back(root_id + 1 - _shape[0]);
614 }
615 // else: not periodic; nothing to add here
616 }
617 else {
618 // Not at boundary; no need for the correction term
619 neighbor_ids.push_back(root_id + 1);
620 }
621 }
622 // top-left and bottom-right
623 else if constexpr (axis == 1) {
624 // Compute normalized ids
625 const IndexType nrm_id_0 = root_id % _shape[0]; // column
626 const IndexType nrm_id_1 = ( (root_id % (_shape[0] * _shape[1]))
627 / _shape[0]); // row
628
629 // Check if at low value boundary
630 if (nrm_id_1 == 0) {
631 // bottom row
632 if constexpr (periodic) {
633 if (nrm_id_0 < _shape[0] - 1) {
634 neighbor_ids.push_back( root_id - _shape[0] + 1
635 + _shape[0] * _shape[1]);
636 }
637 else {
638 // also right most
639 neighbor_ids.push_back( root_id - 2*_shape[0] + 1
640 + _shape[0] * _shape[1]);
641 }
642 }
643 // else: not periodic; nothing to add here
644 }
645 else if (nrm_id_0 == _shape[0] - 1 and nrm_id_1 % 2 == 0) {
646 // right column, offset rows
647 if constexpr (periodic) {
648 neighbor_ids.push_back(root_id - 2*_shape[0] + 1);
649 }
650 // else: not periodic; nothing to add here
651 }
652 else if (nrm_id_1 % 2 == 0) {
653 // offset row
654 // Not at boundary; no need for the correction term
655 neighbor_ids.push_back(root_id - _shape[0] + 1);
656 }
657 else {
658 // non-offset row
659 neighbor_ids.push_back(root_id - _shape[0]);
660 }
661
662 // Check if at high value boundary
663 if (nrm_id_1 == _shape[1] - 1) {
664 // top row
665 if constexpr (periodic) {
666 if (nrm_id_0 > 0) {
667 // is an non-offset row
668 neighbor_ids.push_back( root_id + _shape[0] - 1
669 - _shape[0] * _shape[1]);
670 }
671 else {
672 // left most cell
673 neighbor_ids.push_back( root_id + 2*_shape[0] - 1
674 - _shape[0] * _shape[1]);
675 }
676 }
677 // else: not periodic; nothing to add here
678 }
679 else if (nrm_id_0 == 0 and nrm_id_1 % 2 == 1){
680 // left column impair row
681 if constexpr (periodic) {
682 neighbor_ids.push_back(root_id + 2*_shape[0] - 1);
683 }
684 }
685 else if (nrm_id_1 % 2 == 0) {
686 // Not at boundary; no need for the correction term
687 neighbor_ids.push_back(root_id + _shape[0]);
688 }
689 else {
690 // non-offset row
691 neighbor_ids.push_back(root_id + _shape[0] - 1);
692 }
693 }
694 // top right and bottom left
695 else {
696 // Compute normalized ids
697 const IndexType nrm_id_0 = root_id % _shape[0]; // column
698 const IndexType nrm_id_1 = ( (root_id % (_shape[0] * _shape[1]))
699 / _shape[0]); // row
700
701 if (nrm_id_1 == 0) {
702 // bottom row
703 if constexpr (periodic) {
704 neighbor_ids.push_back( root_id - _shape[0]
705 + _shape[0] * _shape[1]);
706 }
707 // else: not periodic; nothing to add here
708 }
709 else if (nrm_id_0 == 0 and nrm_id_1 % 2 == 1) {
710 // left most, non-offset row
711 if constexpr (periodic) {
712 neighbor_ids.push_back(root_id - 1);
713 }
714 // else: not periodic; nothing to add here
715 }
716 else if (nrm_id_1 % 2 == 1) {
717 neighbor_ids.push_back(root_id - _shape[0] - 1);
718 }
719 else {
720 neighbor_ids.push_back(root_id - _shape[0]);
721 }
722
723 if (nrm_id_1 == _shape[1] - 1) {
724 // top row
725 if constexpr (periodic) {
726 neighbor_ids.push_back( root_id + _shape[0]
727 - _shape[0] * _shape[1]);
728 }
729 // else: not periodic; nothing to add here
730 }
731 else if (nrm_id_0 == _shape[0] - 1 and nrm_id_1 % 2 == 0) {
732 // right column in offset row
733 if constexpr (periodic) {
734 neighbor_ids.push_back(root_id + 1);
735 }
736 // else: not periodic; nothing to add here
737 }
738 else if (nrm_id_1 % 2 == 0) {
739 neighbor_ids.push_back(root_id + _shape[0] + 1);
740 }
741 else {
742 neighbor_ids.push_back(root_id + _shape[0]);
743 }
744 }
745 }
746
747
748 // .. Neighborhood parameter extraction helpers ...........................
749
751
763 template<bool check_shape=false>
765 const auto distance = get_as<DistType>("distance", params, 1);
766
767 // Check the value is smaller than the grid shape. It needs to fit into
768 // the shape of the grid, otherwise all the algorithms above would have
769 // to check for duplicate entries and be set-based, which would be
770 // very inefficient.
771 if constexpr (check_shape) {
772 if ( this->is_periodic()
773 and (distance * 2 + 1 > this->shape().min()))
774 {
775 // To inform about the grid shape, print it to the stringstream
776 // and include it in the error message below.
777 std::stringstream shape_ss;
778 this->shape().print(shape_ss, "Grid Shape:");
779
780 throw std::invalid_argument("The grid shape is too small to "
781 "accomodate a neighborhood with 'distance' parameter set "
782 "to " + get_as<std::string>("distance", params, "1")
783 + " in a periodic space!\n" + shape_ss.str());
784 }
785 }
786
787 return distance;
788 }
789};
790
791
792// end group CellManager
797} // namespace Utopia
798
799#endif // UTOPIA_CORE_GRIDS_HEXAGONAL_HH
The base class for all grid discretizations used by the CellManager.
Definition base.hh:99
bool is_periodic() const
Whether the space this grid maps to is periodic.
Definition base.hh:304
const std::shared_ptr< Space > _space
The space that is to be discretized.
Definition base.hh:120
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
const NBMode & nb_mode() const
Const reference to the currently selected neighborhood mode.
Definition base.hh:198
const Config & nb_params() const
The neighborhood parameters of the currently selected neighborhood.
Definition base.hh:203
A grid discretization using hexagonal cells.
Definition hexagonal.hh:50
std::set< IndexType > boundary_cells(std::string select="all") const override
Retrieve a set of cell indices that are at a specified boundary.
Definition hexagonal.hh:307
typename Space::SpaceVec SpaceVec
The type of vectors that have a relation to physical space.
Definition hexagonal.hh:59
HexagonalGrid(std::shared_ptr< Space > space, const Config &cfg)
Construct a hexagonal grid discretization.
Definition hexagonal.hh:84
MultiIndex shape() const override
Get shape of the hexagonal grid.
Definition hexagonal.hh:146
SpaceVec extent_of(const IndexType) const override
Returns the extent of the cell with the given ID.
Definition hexagonal.hh:186
NBFuncID< Base > get_nb_func_hexagonal(const Config &nb_params)
Returns a standalone hexagonal neighborhood function.
Definition hexagonal.hh:492
NBFuncID< Base > _nb_hexagonal_nonperiodic
The Von-Neumann neighborhood for non-periodic grids.
Definition hexagonal.hh:544
const SpaceVec _cell_extent
The extent of each cell of this discretization (same for all)
Definition hexagonal.hh:76
MultiIndex determine_shape() const
Get shape of the hexagonal grid.
Definition hexagonal.hh:413
void add_neighbors_in_(const IndexType root_id, IndexContainer &neighbor_ids) const
Add both direct neighbors to a container of indices.
Definition hexagonal.hh:585
GridStructure structure() const override
Structure of the grid.
Definition hexagonal.hh:151
NBFuncID< Base > get_nb_func(NBMode nb_mode, const Config &nb_params) override
Retrieve the neighborhood function depending on the mode.
Definition hexagonal.hh:439
IndexType num_cells() const override
Number of hexagonal cells required to fill the physical space.
Definition hexagonal.hh:135
SpaceVec effective_resolution() const override
The effective cell resolution into each physical space dimension.
Definition hexagonal.hh:140
static constexpr DimType dim
The dimensionality of the space to be discretized (for easier access)
Definition hexagonal.hh:56
const MultiIndex _shape
The (multi-index) shape of the grid, resulting from resolution.
Definition hexagonal.hh:71
DistType expected_num_neighbors(const NBMode &nb_mode, const Config &) const override
Computes the expected number of neighbors for a neighborhood mode.
Definition hexagonal.hh:456
SpaceVec barycenter_of(const IndexType id) const override
Returns the barycenter of the cell with the given ID.
Definition hexagonal.hh:167
DistType get_nb_param_distance(const Config &params) const
Extract the distance neighborhood parameter from the given config.
Definition hexagonal.hh:764
DataIO::Config Config
The configuration type.
Definition hexagonal.hh:65
std::vector< SpaceVec > vertices_of(const IndexType id) const override
Returns the vertices of the cell with the given ID.
Definition hexagonal.hh:197
MultiIndexType< dim > MultiIndex
The type of multi-index like arrays, e.g. the grid shape.
Definition hexagonal.hh:62
NBFuncID< Base > _nb_hexagonal_periodic
The Von-Neumann neighborhood for periodic grids.
Definition hexagonal.hh:522
IndexType cell_at(const SpaceVec &pos) const override
Return the ID of the cell covering the given point in physical space.
Definition hexagonal.hh:248
MultiIndex midx_of(const IndexType id) const override
Returns the multi-index of the cell with the given ID.
Definition hexagonal.hh:160
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
@ hexagonal
The hexagonal neighbourhood, i.e. the neighbourhood on a hexagonal grid.
@ empty
Every entity is utterly alone in the world.
@ hexagonal
A hexagonal lattice grid.
YAML::Node Config
Type of a variadic dictionary-like data structure used throughout Utopia.
Definition types.hh:71
Container select_entities(const Manager &mngr, const DataIO::Config &sel_cfg)
Select entities according to parameters specified in a configuration.
Definition select.hh:213
@ vertices
Iterate over vertices.
Definition agent.hh:11
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