Utopia 2
Framework for studying models of complex & adaptive systems.
Loading...
Searching...
No Matches
env_state_func_collection.hh
Go to the documentation of this file.
1#ifndef UTOPIA_MODELS_ENVIRONMENT_ENVSTATEFUNCCOLLECTION_HH
2#define UTOPIA_MODELS_ENVIRONMENT_ENVSTATEFUNCCOLLECTION_HH
3
4#include "tools.hh"
5
7namespace StateFunctionCollection {
8
11
12// -- Helper functions --------------------------------------------------------
13
15
18template<typename EnvModel, class DistType,
19 class EnvStateFunc = typename EnvModel::EnvStateFunc>
20EnvStateFunc
22 DistType&& dist,
23 const std::string& param_name,
24 const ValMode& mode)
25{
26 // NOTE It is VITAL to move-construct the perfectly-forwarded dist into
27 // the lambda; otherwise it has to be stored outside, which is a
28 // real pita. Also, the lambda has to be declared mutable such
29 // that the captured object are allowed to be changed; again, this
30 // is only relevant for the distribution's internal state ...
31 return
32 [&model, param_name, mode, dist{std::move(dist)}]
33 (const auto& env_cell) mutable {
34 auto& env_state = env_cell->state;
35
36 double current_value = 0.;
37 if (mode == ValMode::Add) {
38 current_value = env_state.get_env(param_name);
39 }
40 const double rn = dist(*model.get_rng());
41
42 env_state.set_env(param_name, current_value + rn);
43 return env_state;
44 };
45}
46
51// -- Environment state modification functions --------------------------------
52// .. Keep these in alphabetical order and prefix with _esf_ ! .............
53// NOTE The methods below do _not_ change any state, they just generate
54// a function object that does so at the desired point in time.
55
57
75template<typename EnvModel,
76 class EnvStateFunc = typename EnvModel::EnvStateFunc>
77std::pair<EnvStateFunc, Update> esf_noise(const EnvModel& model,
78 const std::string& param_name,
79 const Config& cfg)
80{
81 const auto mode = extract_val_mode(cfg, "noise");
82 const auto distribution = get_as<std::string>("distribution", cfg);
83
84 // Depending on chosen distribution, construct it and build a rule
85 // function using a reference to the newly created one...
86 if (distribution == "normal") {
87 const auto mean = get_as<double>("mean", cfg);
88 const auto stddev = get_as<double>("stddev", cfg);
89 std::normal_distribution<> dist(mean, stddev);
90
91 auto esf = build_rng_env_state_func(model, std::move(dist), param_name,
92 mode);
93 return {esf, Update::sync};
94 }
95 else if (distribution == "poisson") {
96 const auto mean = get_as<double>("mean", cfg);
97 std::poisson_distribution<> dist(mean);
98
99 auto esf = build_rng_env_state_func(model, std::move(dist), param_name,
100 mode);
101 return {esf, Update::sync};
102 }
103 else if (distribution == "exponential") {
104 const auto lambda = get_as<double>("lambda", cfg);
105 std::exponential_distribution<> dist(lambda);
106
107 auto esf = build_rng_env_state_func(model, std::move(dist), param_name,
108 mode);
109 return {esf, Update::sync};
110 }
111 else if (distribution == "uniform_int") {
112 auto interval = get_as<std::array<int, 2>>("interval", cfg);
113 std::uniform_int_distribution<> dist(interval[0], interval[1]);
114
115 auto esf = build_rng_env_state_func(model, std::move(dist), param_name,
116 mode);
117 return {esf, Update::sync};
118 }
119 else if (distribution == "uniform_real" or distribution == "uniform") {
120 auto interval = get_as<std::array<double, 2>>("interval", cfg);
121 std::uniform_real_distribution<> dist(interval[0], interval[1]);
122
123 auto esf = build_rng_env_state_func(model, std::move(dist), param_name,
124 mode);
125 return {esf, Update::sync};
126 }
127 else {
128 throw std::invalid_argument("No method implemented to resolve "
129 "noise distribution '" + distribution + "'! Valid options: "
130 "normal, poisson, uniform_int, uniform_real.");
131 }
132};
133
135
149template<typename EnvModel, typename Extent,
150 class EnvStateFunc = typename EnvModel::EnvStateFunc>
151std::pair<EnvStateFunc, Update> esf_slope(const EnvModel&,
152 const std::string& param_name,
153 const Config& cfg,
154 const Extent& extent)
155{
156 const auto mode = extract_val_mode(cfg, "slope");
157
158 const auto values_north_south =
159 get_as<std::array<double, 2>>("values_north_south", cfg);
160
161 EnvStateFunc esf =
162 [param_name, mode, values_north_south, extent]
163 (const auto& env_cell) mutable
164 {
165 auto& env_state = env_cell->state;
166
167 // Use the relative position along y-dimension
168 const double pos = ( env_state.position[1] / extent[1]);
169 const double slope = values_north_south[0] - values_north_south[1];
170 const double value = values_north_south[1] + pos * slope;
171
172 double current_value = 0.;
173 if (mode == ValMode::Add) {
174 current_value = env_state.get_env(param_name);
175 }
176 env_state.set_env(param_name, current_value + value);
177 return env_state;
178 };
179
180 return {esf, Update::sync};
181};
182
184
199template<typename EnvModel,
200 class EnvStateFunc = typename EnvModel::EnvStateFunc>
201std::pair<EnvStateFunc, Update> esf_steps(const EnvModel&,
202 const std::string& param_name,
203 const Config& cfg)
204{
205 const auto mode = extract_val_mode(cfg, "steps");
206
207 const auto latitudes =
208 get_as<std::vector<double>>("latitudes", cfg, {0.5});
209 const auto values_north_south =
210 get_as<std::vector<double>>("values_north_south", cfg);
211
212 if (latitudes.size() != values_north_south.size() - 1) {
213 throw std::invalid_argument("The list of 'latitudes' and"
214 " 'values_north_south' don't match in size. Sizes were "
215 + std::to_string(latitudes.size()) + " and "
216 + std::to_string(values_north_south.size()) +
217 ". Values_north_south must have one element more that"
218 " latitudes.");
219 }
220
221 EnvStateFunc esf =
222 [param_name, mode, latitudes, values_north_south]
223 (const auto& env_cell) mutable
224 {
225 auto& env_state = env_cell->state;
226 double value = values_north_south[0];
227 for (unsigned int i = 0; i < latitudes.size(); ++i) {
228 if (env_state.position[1] > latitudes[i]) {
229 break;
230 }
231 value = values_north_south[i+1];
232 }
233
234 double current_value = 0.;
235 if (mode == ValMode::Add) {
236 current_value = env_state.get_env(param_name);
237 }
238 env_state.set_env(param_name, current_value + value);
239 return env_state;
240 };
241
242 return {esf, Update::sync};
243};
244
246
258template<typename EnvModel,
259 class EnvStateFunc = typename EnvModel::EnvStateFunc>
260std::pair<EnvStateFunc, Update> esf_uniform(const EnvModel&,
261 const std::string& param_name,
262 const Config& cfg)
263{
264 ValMode mode;
265 double value;
266
267 // Extract configuration depending on whether cfg is scalar or mapping
268 if (cfg.IsScalar()) {
269 // Interpret as desiring to set to the given scalar value
270 mode = ValMode::Set;
271 value = cfg.as<double>();
272 }
273 else if (cfg.IsMap()) {
274 mode = extract_val_mode(cfg, "uniform");
275 value = get_as<double>("value", cfg);
276 }
277 else {
278 throw std::invalid_argument("The configuration for environment "
279 "function 'uniform' must be a scalar or a mapping!");
280 }
281
282 EnvStateFunc esf =
283 [param_name, mode, value]
284 (const auto& env_cell) mutable
285 {
286 auto& env_state = env_cell->state;
287
288 double current_value = 0.;
289 if (mode == ValMode::Add) {
290 current_value = env_state.get_env(param_name);
291 }
292
293 env_state.set_env(param_name, current_value + value);
294 return env_state;
295 };
296
297 return {esf, Update::sync};
298}
299
300// End group Environment
305} // namespace StateFunctionCollection
306} // namespace Utopia::Models::Environment
307
308#endif
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
std::pair< EnvStateFunc, Update > esf_uniform(const EnvModel &, const std::string &param_name, const Config &cfg)
Creates a rule function for spatially uniform parameter values.
Definition env_state_func_collection.hh:260
ValMode extract_val_mode(const DataIO::Config &cfg, const std::string &context)
Given a configuration node, extract the value mode.
Definition tools.hh:19
std::pair< EnvStateFunc, Update > esf_noise(const EnvModel &model, const std::string &param_name, const Config &cfg)
Creates a rule function for noisy parameter values.
Definition env_state_func_collection.hh:77
std::pair< EnvStateFunc, Update > esf_steps(const EnvModel &, const std::string &param_name, const Config &cfg)
Creates a rule function for spatial steps in the parameter values.
Definition env_state_func_collection.hh:201
std::pair< EnvStateFunc, Update > esf_slope(const EnvModel &, const std::string &param_name, const Config &cfg, const Extent &extent)
Creates a rule function for spatially linearly parameter values.
Definition env_state_func_collection.hh:151
ValMode
Value calculation mode.
Definition tools.hh:10
@ Set
Set a value, discarding the current state.
@ Add
Add the new value to the existing value.
@ sync
Synchronous update.
EnvStateFunc build_rng_env_state_func(EnvModel &model, DistType &&dist, const std::string &param_name, const ValMode &mode)
Create a rule function that uses a random number distribution.
Definition env_state_func_collection.hh:21
DataIO::Config Config
Configuration node type alias.
Definition env_state_func_collection.hh:10
Definition env_param_func_collection.hh:8
unsigned int DistType
Type for distancens, i.e. intermediately long unsigned integers.
Definition types.hh:37