Utopia 2
Framework for studying models of complex & adaptive systems.
Loading...
Searching...
No Matches
PredatorPrey.hh
Go to the documentation of this file.
1#ifndef UTOPIA_MODELS_PREDATORPREY_HH
2#define UTOPIA_MODELS_PREDATORPREY_HH
3
4#include <cstdint>
5#include <algorithm>
6#include <random>
7
11
12#include "species.hh"
13
14
15namespace Utopia {
16namespace Models {
17namespace PredatorPrey {
18
19// ++ Type definitions ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20
22struct State {
25
28
31
33 template<class RNGType>
34 State(const DataIO::Config& cfg, const std::shared_ptr<RNGType>& rng)
35 :
36 predator{},
37 prey{},
39 {
40 std::uniform_real_distribution<double> dist(0., 1.);
41
42 // Get the threshold probability value
43 const auto p_prey = get_as<double>("p_prey", cfg);
44 const auto p_predator = get_as<double>("p_predator", cfg);
45
46 // Set a prey on a cell with the given probability by generating a
47 // random number in [0, 1) and compare it to wanted probability.
48 if (dist(*rng) < p_prey){
49 prey.on_cell = true;
50 prey.resources = get_as<double>("init_resources",
51 cfg["prey"]);
52 }
53
54 // Set a predator on a cell with the given probability.
55 if (dist(*rng) < p_predator){
56 predator.on_cell = true;
57 predator.resources = get_as<double>("init_resources",
58 cfg["predator"]);
59 }
60 }
61};
62
63
65
70
73
74
75// ++ Model definition ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
76
78
93 : public Model<PredatorPrey, ModelTypes>
94{
95public:
98
100 using DataSet = typename Base::DataSet;
101
104
106 using Cell = typename CellManager::Cell;
107
109 using Rule = typename CellManager::RuleFunc;
110
111
112private:
113 // Base members: _time, _name, _cfg, _hdfgrp, _rng, _monitor, _log, _space
114 // ... but you should definitely check out the documentation ;)
115
116 // -- Members -------------------------------------------------------------
119
120 // .. Model parameters ....................................................
123
124 // .. Temporary objects ...................................................
127
130
133
134 // Uniform real distribution [0, 1) for evaluating probabilities
135 std::uniform_real_distribution<double> _prob_distr;
136
137
138 // .. Datasets ............................................................
140 const std::shared_ptr<DataSet> _dset_prey;
141
143 const std::shared_ptr<DataSet> _dset_predator;
144
146 const std::shared_ptr<DataSet> _dset_resource_prey;
147
149 const std::shared_ptr<DataSet> _dset_resource_predator;
150
151
152 // .. Rule functions and helper methods ...................................
154
158 Rule _cost_of_living = [this](const auto& cell) {
159 // Get the state of the cell
160 auto& state = cell->state;
161
162 // Subtract the cost of living and clamp the resources to the limits:
163 // If the resources exceed the maximal resources they are equal to
164 // the maximal resources and if they go below 0 they are mapped to 0.
165 state.predator.resources =
166 std::clamp( state.predator.resources
169 state.prey.resources =
170 std::clamp( state.prey.resources
173
174 // Remove predators that have no resources.
175 if (state.predator.on_cell and state.predator.resources <= 0.) {
176 state.predator.on_cell = false;
177 }
178
179 // Remove prey that have no resources.
180 if (state.prey.on_cell and state.prey.resources <= 0.) {
181 state.prey.on_cell = false;
182 }
183
184 return state;
185 };
186
188
191 void move_predator_to_nb_cell(const std::shared_ptr<Cell>& cell,
192 const std::shared_ptr<Cell>& nb_cell) {
193 auto& state = cell->state;
194 auto& nb_state = nb_cell->state;
195
196 nb_state.predator.on_cell = true;
197 nb_state.predator.resources = state.predator.resources;
198
199 state.predator.on_cell = false;
200 state.predator.resources = 0.;
201 }
202
204
207 void move_prey_to_nb_cell(const std::shared_ptr<Cell>& cell,
208 const std::shared_ptr<Cell>& nb_cell) {
209 auto& state = cell->state;
210 auto& nb_state = nb_cell->state;
211
212 nb_state.prey.on_cell = true;
213 nb_state.prey.resources = state.prey.resources;
214
215 state.prey.on_cell = false;
216 state.prey.resources = 0.;
217 }
218
220
225 Rule _move_predator = [this](const auto& cell) {
226 // Get the state of the Cell
227 auto& state = cell->state;
228
229 // Case: only a predator is on the cell
230 if ((state.predator.on_cell) and (not state.moved_predator)) {
231 // checking neighbouring cells for prey and moving to that cell
232
233 // clear the containers for cells that contain prey or empty cells
234 // in the neighbourhood
235 _prey_cell.clear();
236 _empty_cell.clear();
237
238 for (const auto& nb : this->_cm.neighbors_of(cell)) {
239 auto& nb_state = nb->state;
240
241 if ((nb_state.prey.on_cell) and (not nb_state.predator.on_cell)) {
242 _prey_cell.push_back(nb);
243 }
244 // if neither a prey nor a predator is on the cell, then
245 // it is empty
246 else if (not nb_state.predator.on_cell) {
247 _empty_cell.push_back(nb);
248 }
249 }
250
251 // if there is prey in the vicinity move the predator to a random
252 // prey cell
253 if (_prey_cell.size() > 0) {
254 // distribution to choose a random cell for the movement if
255 // there is more than one
256 std::uniform_int_distribution<>
257 dist_prey(0, _prey_cell.size() - 1);
258
259 // Select a random neighbor cell and move the predator to it
260 auto nb_cell = _prey_cell[dist_prey(*this->_rng)];
261 // Mark target cell as cell with moved predator
262 nb_cell->state.moved_predator=true;
264 }
265
266 // if there is no prey the predator makes a random move
267 else if (_empty_cell.size() > 0) {
268 // distribution to choose a random cell for the movement if
269 // there is more than one
270 std::uniform_int_distribution<>
271 dist_empty(0, _empty_cell.size() - 1);
272
273 // Select a random empty neighbor cell and move the predator
274 // to it
275 auto nb_cell = _empty_cell[dist_empty(*this->_rng)];
276 // Mark target cell as cell with moved predator
277 nb_cell->state.moved_predator=true;
279 }
280 }
281 return state;
282 };
283
285
288 Rule _flee_prey = [this](const auto& cell) {
289 auto& state = cell->state;
290
291 if (state.prey.on_cell and state.predator.on_cell) {
292 // Flee, if possible, with a given flee probability
293 if (this->_prob_distr(*this->_rng) < _params.prey.p_flee){
294 // Collect empty neighboring cells to which the prey could flee
295 _empty_cell.clear();
296 for (const auto& nb : this->_cm.neighbors_of(cell)) {
297 if ( (not nb->state.prey.on_cell)
298 and (not nb->state.predator.on_cell)) {
299 _empty_cell.push_back(nb);
300 }
301 }
302
303 // If there is an empty cell, move there
304 if (_empty_cell.size() > 0) {
305 // Choose a random cell to move to
306 std::uniform_int_distribution<>
307 dist(0, _empty_cell.size() - 1);
308
309 auto nb_cell = _empty_cell[dist(*this->_rng)];
311 }
312 }
313 }
314 return state;
315 // NOTE Should the case be added that the neighboring cell has a predator?
316 // In case that there are no empty cells.
317 // Then the prey has again a small probability to flee in the next
318 // round.
319 };
320
322
327 Rule _eat = [this](const auto& cell) {
328 // Get the state of the cell
329 auto& state = cell->state;
330
331 // Predator eats prey
332 if (state.predator.on_cell and state.prey.on_cell) {
333 // Increase the predator's resources and assure that the resource
334 // maximum is not exceeded by clamping into the correct interval.
335 state.predator.resources = std::clamp(
336 state.predator.resources
338 0.,
340
341 // Remove the prey from the cell
342 state.prey.on_cell = false;
343 state.prey.resources = 0.;
344 }
345
346 // Prey eats grass
347 else if (state.prey.on_cell == true) {
348 // Increase the resources and clamp to the allowed range
349 // [0, resource_max]
350 state.prey.resources = std::clamp(
351 state.prey.resources
353 0.,
355 }
356 return state;
357 };
358
360
363 Rule _repro = [this](const auto& cell) {
364 // Get the state of the cell
365 auto& state = cell->state;
366
367 // Reproduce predators
368 if ( state.predator.on_cell
369 and (this->_prob_distr(*this->_rng) < _params.predator.repro_prob)
370 and (state.predator.resources >= _params.predator.repro_resource_requ))
371 {
372 // Collect available neighboring spots without predators
373 _repro_cell.clear();
374 for (const auto& nb : this->_cm.neighbors_of(cell)) {
375 if (not nb->state.predator.on_cell) {
376 _repro_cell.push_back(nb);
377 }
378 }
379
380 // Choose an available neighboring cell to put an offspring on
381 if (_repro_cell.size() > 0) {
382 // choose a random cell for the offspring to be placed on
383 std::uniform_int_distribution<> dist(0, _repro_cell.size()-1);
384 const auto& nb_cell = _repro_cell[dist(*this->_rng)];
385 auto& nb_state = nb_cell->state;
386
387 // neighboring cell has now a predator.
388 // Congratulations to your new baby! :)
389 nb_state.predator.on_cell = true;
390
391 // transfer resources from parent to offspring
392 nb_state.predator.resources = _params.predator.repro_cost;
393 state.predator.resources -= _params.predator.repro_cost;
394 }
395 }
396
397 // Reproduce prey
398 if ( state.prey.on_cell
399 and this->_prob_distr(*this->_rng) < _params.prey.repro_prob
400 and state.prey.resources >= _params.prey.repro_resource_requ)
401 {
402 _repro_cell.clear();
403
404 for (const auto& nb : this->_cm.neighbors_of(cell)) {
405 if (not nb->state.prey.on_cell) {
406 _repro_cell.push_back(nb);
407 }
408 }
409
410 if (_repro_cell.size() > 0) {
411 // choose a random cell for the offspring to be placed on
412 std::uniform_int_distribution<> dist(0, _repro_cell.size() - 1);
413 // TODO Use std::sample
414
415 auto nb_cell = _repro_cell[dist(*this->_rng)];
416
417 // neighboring cell has now a prey.
418 // Congratulations to your new baby! :)
419 nb_cell->state.prey.on_cell = true;
420
421 // transfer energy from parent to offspring
422 nb_cell->state.prey.resources = _params.prey.repro_cost;
423 state.prey.resources -= _params.prey.repro_cost;
424
425 // NOTE Should there be some dissipation of resources during
426 // reproduction?
427 }
428 }
429 return state;
430 };
431
434 auto& state = cell->state;
435 state.moved_predator = false;
436 return state;
437 };
438
439
440public:
441 // -- Model setup ---------------------------------------------------------
443
451 template <class ParentModel>
453 const std::string& name,
455 const DataIO::Config& custom_cfg = {}
456 )
457 :
459 // Initialize the cell manager, binding it to this model
460 _cm(*this),
461
462 // Extract model parameters
463 _params(this->_cfg),
464
465 // Temporary cell containers
466 _prey_cell(),
467 _empty_cell(),
468 _repro_cell(),
469
470 // Initialize distributions
471 _prob_distr(0., 1.),
472
473 // Create datasets
475 _dset_predator(this->create_cm_dset("predator", _cm)),
476 _dset_resource_prey(this->create_cm_dset("resource_prey", _cm)),
477 _dset_resource_predator(this->create_cm_dset("resource_predator", _cm))
478 {
479 // Load the cell state from a file, overwriting the current state
480 if (this->_cfg["cell_states_from_file"]) {
481 const auto& cs_cfg = this->_cfg["cell_states_from_file"];
482 const auto hdf5_file = get_as<std::string>("hdf5_file", cs_cfg);
483 const auto predator_init_resources = get_as<double>("init_resources",
484 this->_cfg["cell_manager"]["cell_params"]["predator"]);
485 const auto prey_init_resources = get_as<double>("init_resources",
486 this->_cfg["cell_manager"]["cell_params"]["prey"]);
487 if (get_as<bool>("load_predator", cs_cfg)) {
488 this->_log->info("Loading predator positions from file ...");
489
490 // Use the CellManager to set the cell state from the data
491 // given by the `predator` dataset. Load as int to be able to
492 // detect that a user supplied invalid values (better than
493 // failing silently, which would happen with booleans).
494 _cm.set_cell_states<int>(hdf5_file, "predator",
495 [predator_init_resources](auto& cell, const int on_cell){
496 if (on_cell == 0 or on_cell == 1) {
497 cell->state.predator.on_cell = on_cell;
498 if(on_cell == 1){
499 cell->state.predator.resources =
501 }
502 else{
503 cell->state.predator.resources = 0;
504 }
505 return;
506 }
507 throw std::invalid_argument("While setting predator "
508 "positions, encountered an invalid value: "
509 + std::to_string(on_cell) + ". Allowed: 0 or 1.");
510 }
511 );
512
513 this->_log->info("Predator positions loaded.");
514 }
515
516 if (get_as<bool>("load_prey", cs_cfg)) {
517 this->_log->info("Loading prey positions from file ...");
518
519 _cm.set_cell_states<int>(hdf5_file, "prey",
520 [prey_init_resources](auto& cell, const int on_cell){
521 if (on_cell == 0 or on_cell == 1) {
522 cell->state.prey.on_cell = on_cell;
523 if(on_cell == 1){
524 cell->state.prey.resources =
526 }
527 else{
528 cell->state.prey.resources = 0;
529 }
530 return;
531 }
532 throw std::invalid_argument("While setting prey "
533 "positions, encountered an invalid value: "
534 + std::to_string(on_cell) + ". Allowed: 0 or 1.");
535 }
536 );
537
538 this->_log->info("Prey positions loaded.");
539 }
540 }
541
542 // Reserve memory in the size of the neighborhood for the temp. vectors
543 const auto nb_size = _cm.nb_size();
544 _prey_cell.reserve(nb_size);
545 _empty_cell.reserve(nb_size);
546 _repro_cell.reserve(nb_size);
547
548 // Initialization finished
549 this->_log->info("{} model fully set up.", this->_name);
550 }
551
552public:
553 // -- Public Interface ----------------------------------------------------
554 // .. Simulation Control ..................................................
555
557
583
585 void monitor () {
587 auto [pred_density, prey_density] = [this](){
588 double predator_sum = 0.;
589 double prey_sum = 0.;
590 double num_cells = this->_cm.cells().size();
591
592 for (const auto& cell : this->_cm.cells()) {
593 auto state = cell->state;
594
595 if (state.prey.on_cell) {
596 prey_sum++;
597 }
598
599 if (state.predator.on_cell) {
600 predator_sum++;
601 }
602 }
603 return std::pair{predator_sum / num_cells, prey_sum / num_cells};
604 }();
605
606 this->_monitor.set_entry("predator_density", pred_density);
607 this->_monitor.set_entry("prey_density", prey_density);
608 }
609
611
619 void write_data() {
620 // Predator
621 _dset_predator->write(_cm.cells().begin(), _cm.cells().end(),
622 [](const auto& cell) {
623 return static_cast<char>(cell->state.predator.on_cell);
624 }
625 );
626
627 // Prey
628 _dset_prey->write(_cm.cells().begin(), _cm.cells().end(),
629 [](const auto& cell) {
630 return static_cast<char>(cell->state.prey.on_cell);
631 }
632 );
633
634 // resource of predator
635 _dset_resource_predator->write(_cm.cells().begin(), _cm.cells().end(),
636 [](const auto& cell) {
637 return cell->state.predator.resources;
638 }
639 );
640
641 // resource of prey
642 _dset_resource_prey->write(_cm.cells().begin(), _cm.cells().end(),
643 [](const auto& cell) {
644 return cell->state.prey.resources;
645 }
646 );
647 }
648};
649
650} // namespace PredatorPrey
651} // namespace Models
652} // namespace Utopia
653
654#endif // UTOPIA_MODELS_PREDATORPREY_HH
void set_cell_states(const std::string &hdf5_file, const std::string &dset_path, const SetterFunc &setter_func)
Set all cell states using information from a HDF5 file.
Definition cell_manager.hh:388
typename std::function< CellState(const std::shared_ptr< Cell > &)> RuleFunc
The type of a rule function acting on cells of this cell manager.
Definition cell_manager.hh:84
auto nb_size() const
Return the (maximum) size of the currently selected neighborhood.
Definition cell_manager.hh:450
CellContainer< Cell > neighbors_of(const Cell &cell) const
Retrieve the given cell's neighbors.
Definition cell_manager.hh:458
const CellContainer< Cell > & cells() const
Return const reference to the managed CA cells.
Definition cell_manager.hh:219
Utopia::Cell< CellTraits > Cell
Type of the managed cells.
Definition cell_manager.hh:47
Base class interface for Models using the CRT Pattern.
Definition model.hh:112
std::shared_ptr< DataSet > create_cm_dset(const std::string name, const CellManager &cm, const std::size_t compression_level=1, const std::vector< hsize_t > chunksize={})
Create a dataset storing data from a CellManager.
Definition model.hh:849
Monitor _monitor
The monitor.
Definition model.hh:188
typename ModelTypes::DataSet DataSet
Data type that is used for storing data.
Definition model.hh:125
const Config _cfg
Config node belonging to this model instance.
Definition model.hh:158
const std::string _name
Name of the model instance.
Definition model.hh:149
const std::shared_ptr< spdlog::logger > _log
The (model) logger.
Definition model.hh:164
const std::shared_ptr< RNG > _rng
The RNG shared between models.
Definition model.hh:161
PredatorPrey Model on grid cells.
Definition PredatorPrey.hh:94
void perform_step()
Perform an iteration step.
Definition PredatorPrey.hh:564
void move_prey_to_nb_cell(const std::shared_ptr< Cell > &cell, const std::shared_ptr< Cell > &nb_cell)
Move a prey to a neighboring cell.
Definition PredatorPrey.hh:207
typename Base::DataSet DataSet
Data type for a dataset.
Definition PredatorPrey.hh:100
CellContainer< Cell > _empty_cell
A container to temporarily accumulate empty neighbour cells.
Definition PredatorPrey.hh:129
SpeciesParams _params
Predator-specific model parameters.
Definition PredatorPrey.hh:122
Rule _flee_prey
Define the movement rule of prey.
Definition PredatorPrey.hh:288
void monitor()
Monitor model information.
Definition PredatorPrey.hh:585
const std::shared_ptr< DataSet > _dset_predator
Dataset of Predator locations on the grid.
Definition PredatorPrey.hh:143
Rule _cost_of_living
Cost of Living.
Definition PredatorPrey.hh:158
std::uniform_real_distribution< double > _prob_distr
Definition PredatorPrey.hh:135
Rule _reset_predator_movement
Resets the movement flag of predators to "false" for next turn.
Definition PredatorPrey.hh:433
const std::shared_ptr< DataSet > _dset_prey
Dataset of Prey locations on the grid.
Definition PredatorPrey.hh:140
void write_data()
Write data.
Definition PredatorPrey.hh:619
const std::shared_ptr< DataSet > _dset_resource_predator
Dataset of Predator resources on the grid.
Definition PredatorPrey.hh:149
void move_predator_to_nb_cell(const std::shared_ptr< Cell > &cell, const std::shared_ptr< Cell > &nb_cell)
Move a predator to a neighboring cell.
Definition PredatorPrey.hh:191
Rule _repro
Define the reproduction rule.
Definition PredatorPrey.hh:363
typename CellManager::Cell Cell
The type of a cell.
Definition PredatorPrey.hh:106
CellContainer< Cell > _repro_cell
A container to temporarily accumulate neighbour cells for reproduction.
Definition PredatorPrey.hh:132
PredatorPrey(const std::string &name, ParentModel &parent_model, const DataIO::Config &custom_cfg={})
Construct the PredatorPrey model.
Definition PredatorPrey.hh:452
Model< PredatorPrey, ModelTypes > Base
The base model.
Definition PredatorPrey.hh:97
const std::shared_ptr< DataSet > _dset_resource_prey
Dataset of Prey resources on the grid.
Definition PredatorPrey.hh:146
Rule _eat
Define the eating rule.
Definition PredatorPrey.hh:327
CellManager _cm
The cell manager.
Definition PredatorPrey.hh:118
Rule _move_predator
Define the movement rule of predator.
Definition PredatorPrey.hh:225
CellContainer< Cell > _prey_cell
A container to temporarily accumulate the prey neighbour cells.
Definition PredatorPrey.hh:126
typename CellManager::RuleFunc Rule
Type of the update rules.
Definition PredatorPrey.hh:109
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
ModelTypes<> ModelTypes
Typehelper to define data types of PredatorPrey model.
Definition PredatorPrey.hh:72
Definition agent.hh:11
EntityContainer< CellType > CellContainer
Type of the variably sized container for cells.
Definition types.hh:26
The entity traits struct gathers types to be used for specializing an entity.
Definition entity.hh:49
double p_flee
Probability to flee from a predator if on the same cell.
Definition species.hh:87
double resource_intake
Resource intake from eating.
Definition species.hh:33
double repro_cost
Cost of reproduction.
Definition species.hh:43
double resource_max
Maximal resource level.
Definition species.hh:39
double cost_of_living
Cost of living that is taken each time step.
Definition species.hh:30
double repro_resource_requ
Minimal reproduction resources requirements.
Definition species.hh:36
double repro_prob
Reproduction probability.
Definition species.hh:46
The parameter of all species.
Definition species.hh:106
PredatorParams predator
Predator parameters.
Definition species.hh:111
PreyParams prey
Prey parameters.
Definition species.hh:108
Struct that holds all species states.
Definition species.hh:11
double resources
The internal resources reservoir.
Definition species.hh:16
bool on_cell
Whether the species is on the cell.
Definition species.hh:13
Cell State struct.
Definition PredatorPrey.hh:22
State(const DataIO::Config &cfg, const std::shared_ptr< RNGType > &rng)
Construct a cell state with the use of a RNG.
Definition PredatorPrey.hh:34
bool moved_predator
Flag to indicate if the predator on this cell has already moved
Definition PredatorPrey.hh:30
SpeciesState prey
The state a prey on this cell has.
Definition PredatorPrey.hh:27
SpeciesState predator
The state a predator on this cell has.
Definition PredatorPrey.hh:24