Utopia 2
Framework for studying models of complex & adaptive systems.
Loading...
Searching...
No Matches
ContDisease.hh
Go to the documentation of this file.
1#ifndef UTOPIA_MODELS_CONTDISEASE_HH
2#define UTOPIA_MODELS_CONTDISEASE_HH
3
4#include <functional>
5#include <random>
6
7// Utopia-related includes
11#include <utopia/core/select.hh>
12
13// ContDisease-realted includes
14#include "params.hh"
15#include "state.hh"
16
17
19
20// ++ Type definitions ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21
22// Specialize the CellTraits type helper for this model
29
30
33
34
35// ++ Model definition ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
36
38
51 public Model<ContDisease, CDTypes>
52{
53public:
56
58 using DataGroup = typename Base::DataGroup;
59
61 using DataSet = typename Base::DataSet;
62
65
67 using Cell = typename CellManager::Cell;
68
71
74
75private:
76 // Base members: _time, _name, _cfg, _hdfgrp, _rng, _monitor, _space
77 // ... but you should definitely check out the documentation ;)
78
79 // -- Members -------------------------------------------------------------
82
85
87 std::uniform_real_distribution<double> _prob_distr;
88
90 unsigned int _cluster_id_cnt;
91
93 std::vector<std::shared_ptr<CellManager::Cell>> _cluster_members;
94
96
101 std::array<double, 5> _densities;
102
103 // .. Data-Output related members .........................................
105
107 std::shared_ptr<DataSet> _dset_densities;
108
110 std::shared_ptr<DataSet> _dset_kind;
111
113 std::shared_ptr<DataSet> _dset_age;
114
116 std::shared_ptr<DataSet> _dset_cluster_id;
117
118
119public:
121
129 template<class ParentModel>
131 const std::string& name,
133 const DataIO::Config& custom_cfg = {}
134 )
135 :
136 // Initialize first via base model
138
139 // Initialize the cell manager, binding it to this model
140 _cm(*this),
141
142 // Carry over Parameters
143 _params(this->_cfg),
144
145 // Initialize remaining members
146 _prob_distr(0., 1.),
149 _densities{}, // undefined here, will be set in constructor body
150 _write_only_densities(get_as<bool>("write_only_densities",
151 this->_cfg)),
152
153 // Create the dataset for the densities; shape is known
154 _dset_densities(this->create_dset("densities", {5})),
155
156 // Create dataset for cell states
157 _dset_kind(this->create_cm_dset("kind", _cm)),
158
159 // Create dataset for tree age
160 _dset_age(this->create_cm_dset("age", _cm)),
161
162 // Create dataset for cluster id
163 _dset_cluster_id(this->create_cm_dset("cluster_id", _cm))
164 {
165 // Make sure the densities are not undefined
166 _densities.fill(std::numeric_limits<double>::quiet_NaN());
167
168 // Cells are already set up by the CellManager.
169 // Remaining initialization steps regard only macroscopic quantities,
170 // e.g. the setup of heterogeneities: Stones and infection source.
171
172 // Stones
173 if (_cfg["stones"] and get_as<bool>("enabled", _cfg["stones"])) {
174 this->_log->info("Setting cells to be stones ...");
175
176 // Get the container
177 auto to_turn_to_stone = _cm.select_cells(_cfg["stones"]);
178
179 // Apply a rule to all cells of that container: turn to stone
181 [](const auto& cell){
182 auto& state = cell->state;
183 state.kind = Kind::stone;
184 return state;
185 },
187 );
188
189 this->_log->info("Set {} cells to be stones using selection mode "
190 "'{}'.", to_turn_to_stone.size(),
191 get_as<std::string>("mode", _cfg["stones"]));
192 }
193
194 // Ignite some cells permanently: fire sources
195 if ( _cfg["infection_source"]
196 and get_as<bool>("enabled", _cfg["infection_source"]))
197 {
198 this->_log->info("Setting cells to be infection sources ...");
199 auto source_cells = _cm.select_cells(_cfg["infection_source"]);
200
202 [](const auto& cell){
203 auto& state = cell->state;
204 state.kind = Kind::source;
205 return state;
206 },
208 );
209
210 this->_log->info("Set {} cells to be infection sources using "
211 "selection mode '{}'.", source_cells.size(),
212 get_as<std::string>("mode", _cfg["infection_source"]));
213 }
214
215 // Add attributes to density dataset that provide coordinates
216 _dset_densities->add_attribute("dim_name__1", "kind");
217 _dset_densities->add_attribute("coords_mode__kind", "values");
218 _dset_densities->add_attribute("coords__kind",
219 std::vector<std::string>{
220 "empty", "tree", "infected", "source", "stone"
221 });
222 this->_log->debug("Added coordinates to densities dataset.");
223
224 // Initialization should be finished here.
225 this->_log->debug("{} model fully set up.", this->_name);
226 }
227
228protected:
229 // .. Helper functions ....................................................
231
239 // Temporarily overwrite every entry in the densities with zeroes
240 _densities.fill(0);
241
242 // Count the occurrence of each possible state. Use the _densities
243 // member for that in order to not create a new array.
244 for (const auto& cell : this->_cm.cells()) {
245 // Cast enum to integer to arrive at the corresponding index
246 ++_densities[static_cast<char>(cell->state.kind)];
247 }
248 // The _densities array now contains the counts.
249
250 // Calculate the actual densities by dividing the counts by the total
251 // number of cells.
252 for (auto&& d : _densities){
253 d /= static_cast<double>(this->_cm.cells().size());
254 }
255 };
256
257
259
264 // reset cluster counter
265 _cluster_id_cnt = 0;
267 _cm.cells());
268 }
269
271
282 // Check that time matches the first element of the sorted queue of
283 // time steps at which to apply the given number of infections.
285 // Check whether time has come for infections
286 if (this->_time == _params.infection_control.at_times.front()){
287 // Select cells that are trees
288 // (not empty, stones, infected, or source)
289 const auto cells_pool =
291 [&](const auto& cell){
292 return (cell->state.kind == Kind::tree);
293 }
294 );
295
296 // Sample cells from the pool and ...
298 std::sample(
299 cells_pool.begin(), cells_pool.end(),
300 std::back_inserter(sample),
302 *this->_rng
303 );
304
305 // ... and infect the sampled cells
306 for (const auto& cell : sample){
307 cell->state.kind = Kind::infected;
308 }
309
310 // Done. Can now remove first element of the queue.
312 }
313 }
314
315 // Change p_infect if the iteration step matches the ones
316 // specified in the configuration. This leads to constant time lookup.
318 const auto change_p_infect =
320
321 if (this->_time == change_p_infect.first) {
322 _params.p_infect = change_p_infect.second;
323
324 // Done. Can now remove the element from the queue.
326 }
327 }
328 }
329
330 // .. Rule functions ......................................................
331
333
339 RuleFunc _update = [this](const auto& cell){
340 // Get the current state of the cell and reset its cluster ID
341 auto state = cell->state;
342 state.cluster_id = 0;
343
344 // Distinguish by current state
345 if (state.kind == Kind::empty) {
346 // With a probability of p_growth, set the cell's state to tree
347 if (_prob_distr(*this->_rng) < _params.p_growth){
348 state.kind = Kind::tree;
349 return state;
350 }
351 }
352 else if (state.kind == Kind::tree){
353 // Increase the age of the tree
354 ++state.age;
355
356 // Tree can be infected by neighbor or by random-point-infection.
357
358 // Determine whether there will be a point infection
359 if (_prob_distr(*this->_rng) < _params.p_infect) {
360 // Yes, point infection occurred.
361 state.kind = Kind::infected;
362 return state;
363 }
364 else {
365 // Go through neighbor cells (according to Neighborhood type),
366 // and check if they are infected (or an infection source).
367 // If yes, infect cell with the probability 1-p_immunity.
368 for (const auto& nb: this->_cm.neighbors_of(cell)) {
369 // Get the neighbor cell's state
370 auto nb_state = nb->state;
371
372 if ( nb_state.kind == Kind::infected
373 or nb_state.kind == Kind::source)
374 {
375 // With a certain probability, become infected
376 if (_prob_distr(*this->_rng) > _params.p_immunity) {
377 state.kind = Kind::infected;
378 return state;
379 }
380 }
381 }
382 }
383 }
384 else if (state.kind == Kind::infected) {
385 // Decease -> become an empty cell
386 state.kind = Kind::empty;
387
388 // Reset the age of the cell to 0
389 state.age = 0;
390
391 return state;
392 }
393 // else: other cell states need no update
394
395 // Return the (potentially changed) cell state for the next round
396 return state;
397 };
398
400 RuleFunc _identify_cluster = [this](const auto& cell){
401 if (cell->state.cluster_id != 0 or cell->state.kind != Kind::tree) {
402 // already labelled, nothing to do. Return current state
403 return cell->state;
404 }
405 // else: need to label this cell
406
407 // Increment the cluster ID counter and label the given cell
409 cell->state.cluster_id = _cluster_id_cnt;
410
411 // Use existing cluster member container, clear it, add current cell
413 cluster.clear();
414 cluster.push_back(cell);
415
416 // Perform the percolation
417 for (unsigned int i = 0; i < cluster.size(); ++i) {
418 // Iterate over all potential cluster members c, i.e. all
419 // neighbors of cell cluster[i] that is already in the cluster
420 for (const auto& nb : this->_cm.neighbors_of(cluster[i])) {
421 // If it is a tree that is not yet in the cluster, add it.
422 if ( nb->state.cluster_id == 0
423 and nb->state.kind == Kind::tree)
424 {
425 nb->state.cluster_id = _cluster_id_cnt;
426 cluster.push_back(nb);
427 // This extends the outer for-loop...
428 }
429 }
430 }
431
432 return cell->state;
433 };
434
435
436public:
437 // -- Public Interface ----------------------------------------------------
438 // .. Simulation Control ..................................................
439
441
447 void perform_step () {
448 // Apply infection control if enabled
451 }
452
453 // Apply the update rule to all cells.
455 // NOTE The cell state is updated synchronously, i.e.: only after all
456 // cells have been visited and know their state for the next step
457 }
458
459
461
463 void monitor () {
465 this->_monitor.set_entry("densities", _densities);
466 }
467
468
470
473 void write_data () {
474 // Update densities and write them
477 // NOTE Although stones and source density are not changing, they are
478 // calculated anyway and writing them again is not a big cost
479 // (two doubles) while making analysis much easier.
480
481 // If only the densities are to be written, can stop here.
483 return;
484 }
485
486 // Write the cell state
487 _dset_kind->write(_cm.cells().begin(), _cm.cells().end(),
488 [](const auto& cell) {
489 return static_cast<char>(cell->state.kind);
490 }
491 );
492
493 // Write the tree ages
494 _dset_age->write(_cm.cells().begin(), _cm.cells().end(),
495 [](const auto& cell) {
496 return static_cast<unsigned short int>(cell->state.age);
497 }
498 );
499
500 // Identify clusters and write them out
502 _dset_cluster_id->write(_cm.cells().begin(), _cm.cells().end(),
503 [](const auto& cell) {
504 return cell->state.cluster_id;
505 });
506 }
507};
508
509
510} // namespace Utopia::Models::ContDisease
511
512#endif // UTOPIA_MODELS_CONTDISEASE_HH
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
CellContainer< Cell > select_cells(Args &&... args) const
Select cells using the Utopia::select_entities interface.
Definition cell_manager.hh:342
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< CDCellTraits > 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
Time _time
Model-internal current time stamp.
Definition model.hh:170
const std::string _name
Name of the model instance.
Definition model.hh:149
typename ModelTypes::DataGroup DataGroup
Data type that is used for storing datasets.
Definition model.hh:122
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
std::shared_ptr< DataSet > create_dset(const std::string name, const std::shared_ptr< DataGroup > &hdfgrp, std::vector< hsize_t > add_write_shape, const std::size_t compression_level=1, const std::vector< hsize_t > chunksize={})
Create a new dataset within the given group.
Definition model.hh:752
Contagious disease model on a grid.
Definition ContDisease.hh:52
std::array< double, 5 > _densities
Densities for all states.
Definition ContDisease.hh:101
void update_densities()
Update the densities array.
Definition ContDisease.hh:238
RuleFunc _update
Define the update rule.
Definition ContDisease.hh:339
void identify_clusters()
Identify clusters.
Definition ContDisease.hh:263
void write_data()
Write data.
Definition ContDisease.hh:473
typename Base::DataGroup DataGroup
Data type for a data group.
Definition ContDisease.hh:58
void perform_step()
Iterate a single time step.
Definition ContDisease.hh:447
std::shared_ptr< DataSet > _dset_cluster_id
The dataset for storing the cluster ID associated with each cell.
Definition ContDisease.hh:116
RuleFunc _identify_cluster
Identify each cluster of trees.
Definition ContDisease.hh:400
void infection_control()
Apply infection control.
Definition ContDisease.hh:281
typename CellManager::RuleFunc RuleFunc
Rule function type.
Definition ContDisease.hh:73
Utopia::CellContainer< Cell > CellContainer
Type of a container of shared pointers to cells.
Definition ContDisease.hh:70
Model< ContDisease, CDTypes > Base
The base model type.
Definition ContDisease.hh:55
CellManager _cm
The cell manager.
Definition ContDisease.hh:81
unsigned int _cluster_id_cnt
The incremental cluster tag.
Definition ContDisease.hh:90
typename Base::DataSet DataSet
Data type for a dataset.
Definition ContDisease.hh:61
std::shared_ptr< DataSet > _dset_densities
2D dataset (densities array and time) of density values
Definition ContDisease.hh:107
void monitor()
Monitor model information.
Definition ContDisease.hh:463
const Params _params
Model parameters.
Definition ContDisease.hh:84
std::vector< std::shared_ptr< CellManager::Cell > > _cluster_members
A temporary container for use in cluster identification.
Definition ContDisease.hh:93
typename CellManager::Cell Cell
Type of a cell.
Definition ContDisease.hh:67
std::uniform_real_distribution< double > _prob_distr
The range [0, 1] distribution to use for probability checks.
Definition ContDisease.hh:87
ContDisease(const std::string &name, ParentModel &parent_model, const DataIO::Config &custom_cfg={})
Construct the ContDisease model.
Definition ContDisease.hh:130
std::shared_ptr< DataSet > _dset_kind
2D dataset (cell ID and time) of cell kinds
Definition ContDisease.hh:110
bool _write_only_densities
Definition ContDisease.hh:104
std::shared_ptr< DataSet > _dset_age
2D dataset (tree age and time) of cells
Definition ContDisease.hh:113
YAML::Node Config
Type of a variadic dictionary-like data structure used throughout Utopia.
Definition types.hh:71
ReturnType get_as(const std::string &key, const DataIO::Config &node)
This function is a wrapper around the yaml-cpp YAML::Node::as function.
Definition cfg_utils.hh:158
Container select_entities(const Manager &mngr, const DataIO::Config &sel_cfg)
Select entities according to parameters specified in a configuration.
Definition select.hh:213
@ condition
Select if a condition is fulfilled.
@ sample
Select a random sample of entities with a known sample size.
Definition ContDisease.hh:18
@ stone
Cell cannot be infected.
@ source
Cell is an infection source: constantly infected, spreading infection.
@ tree
Cell represents a tree.
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
Wrapper struct for defining model class data types.
Definition model.hh:92
TimesValuesQueue change_p_infect
Change p_infect to new value at given times.
Definition params.hh:37
const std::size_t num_additional_infections
The number of infections added to the default p_infect.
Definition params.hh:27
TimesQueue at_times
Add additional infections at these time steps.
Definition params.hh:30
const bool enabled
Whether infection control is enabled.
Definition params.hh:24
Parameters of the ContDisease.
Definition params.hh:133
const double p_growth
Probability per site and time step to go from state empty to tree.
Definition params.hh:135
const double p_immunity
Definition params.hh:139
double p_infect
Definition params.hh:143
const InfectionContParams infection_control
Infection control parameters.
Definition params.hh:146