Utopia 2
Framework for studying models of complex & adaptive systems.
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Protected Member Functions | Protected Attributes | Static Protected Attributes | Private Member Functions | List of all members
Utopia::Model< Derived, ModelTypes > Class Template Reference

Base class interface for Models using the CRT Pattern. More...

#include <model.hh>

Inheritance diagram for Utopia::Model< Derived, ModelTypes >:
Inheritance graph
[legend]
Collaboration diagram for Utopia::Model< Derived, ModelTypes >:
Collaboration graph
[legend]

Public Types

using Config = typename ModelTypes::Config
 Data type that holds the configuration.
 
using DataManager = DataIO::Default::DefaultDataManager< Derived >
 The data manager to use, specialized with the derived model.
 
using DataGroup = typename ModelTypes::DataGroup
 Data type that is used for storing datasets.
 
using DataSet = typename ModelTypes::DataSet
 Data type that is used for storing data.
 
using RNG = typename ModelTypes::RNG
 Data type of the shared RNG.
 
using Space = typename ModelTypes::Space
 Data type of the space this model resides in.
 
using Time = typename ModelTypes::Time
 Data type for the model time.
 
using Monitor = typename ModelTypes::Monitor
 Data type for the monitor.
 
using MonitorManager = typename ModelTypes::MonitorManager
 Data type for the monitor manager.
 
using Level = typename ModelTypes::Level
 Data type for the hierarchical level.
 

Public Member Functions

template<class ParentModel , class... WriterArgs>
 Model (const std::string &name, const ParentModel &parent_model, const Config &custom_cfg={}, std::tuple< WriterArgs... > w_args={}, const DataIO::Default::DefaultDecidermap< Derived > &w_deciders=DataIO::Default::default_deciders< Derived >, const DataIO::Default::DefaultTriggermap< Derived > &w_triggers=DataIO::Default::default_triggers< Derived >)
 Constructs a Model instance.
 
const std::shared_ptr< Space > & get_space () const
 Return the space this model resides in.
 
Time get_time () const
 Return the current time of this model.
 
Time get_time_max () const
 Return the maximum time possible for this model.
 
Config get_cfg () const
 Return the config node of this model.
 
std::string get_name () const
 Return the name of this model instance.
 
std::string get_full_name () const
 Return the full name of this model within the model hierarchy.
 
std::shared_ptr< DataGroupget_hdfgrp () const
 Return a pointer to the HDF group this model stores data in.
 
Time get_write_start () const
 Return the parameter that controls when write_data is called first.
 
Time get_write_every () const
 Return the parameter that controls how often write_data is called.
 
DataManager get_datamanager () const
 return the datamanager
 
hsize_t get_remaining_num_writes () const
 Return the number of remaining write_data calls this model will make.
 
std::shared_ptr< RNGget_rng () const
 Return a pointer to the shared RNG.
 
std::shared_ptr< spdlog::logger > get_logger () const
 Return a pointer to the logger of this model.
 
Monitor get_monitor () const
 Return the monitor of this model.
 
std::shared_ptr< MonitorManagerget_monitor_manager () const
 Get the monitor manager of the root model.
 
Level get_level () const
 Return the hierarchical level within the model hierarchy.
 
virtual void prolog ()
 A function that is called before starting model iteration.
 
virtual void epilog ()
 A function that is called after the last iteration of a model.
 
void iterate ()
 Iterate one (time) step of this model.
 
void run ()
 Run the model from the current time to the maximum time.
 
std::shared_ptr< DataSetcreate_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.
 
std::shared_ptr< DataSetcreate_dset (const std::string name, const 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 model's base data group.
 
template<class CellManager >
std::shared_ptr< DataSetcreate_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.
 
template<class AgentManager >
std::shared_ptr< DataSetcreate_am_dset (const std::string name, const AgentManager &am, const std::size_t compression_level=1, const std::vector< hsize_t > chunksize={})
 Create a dataset storing data from a AgentManager.
 

Protected Member Functions

void __perform_step ()
 Perform the computation of a step.
 
void __monitor ()
 Monitor information in the terminal.
 
void __write_data ()
 Write data; calls the implementation's write_data method.
 
void __write_initial_state ()
 Write the initial state.
 
void increment_time (const Time dt=1)
 Increment time.
 
void __prolog ()
 The default prolog of a model.
 
void __epilog ()
 The default epilog of a model.
 
Derivedimpl ()
 cast to the derived class
 
const Derivedimpl () const
 const cast to the derived interface
 

Protected Attributes

const std::string _name
 Name of the model instance.
 
const std::string _full_name
 The full name within the model hierarchy.
 
const Level _level
 The level within the model hierarchy.
 
const Config _cfg
 Config node belonging to this model instance.
 
const std::shared_ptr< RNG_rng
 The RNG shared between models.
 
const std::shared_ptr< spdlog::logger > _log
 The (model) logger.
 
std::shared_ptr< Space_space
 The space this model resides in.
 
Time _time
 Model-internal current time stamp.
 
const Time _time_max
 Model-internal maximum time stamp.
 
const std::shared_ptr< DataGroup_hdfgrp
 The HDF group this model instance should write its data to.
 
const Time _write_start
 First time at which write_data is called.
 
const Time _write_every
 How often to call write_data from iterate.
 
Monitor _monitor
 The monitor.
 
DataManager _datamanager
 Manager object for handling data output; see DataManager.
 

Static Protected Attributes

static constexpr WriteMode _write_mode = ModelTypes::write_mode
 Which data-writing mode the base model should use.
 

Private Member Functions

template<class Parent >
auto setup_logger (const Parent &parent_model) const
 Constructs this models logger instance from the parent.
 
auto setup_space () const
 Constructs the Space from configuration or uses the default Space.
 
void __attach_sig_handlers () const
 Attaches signal handlers: SIGINT, SIGTERM, SIGUSR1.
 

Detailed Description

template<class Derived, typename ModelTypes>
class Utopia::Model< Derived, ModelTypes >

Base class interface for Models using the CRT Pattern.

Template Parameters
DerivedType of the derived model class
ModelTypesTraits of this model, can be used for specializing

Member Typedef Documentation

◆ Config

Data type that holds the configuration.

◆ DataGroup

Data type that is used for storing datasets.

◆ DataManager

The data manager to use, specialized with the derived model.

◆ DataSet

Data type that is used for storing data.

◆ Level

Data type for the hierarchical level.

◆ Monitor

Data type for the monitor.

◆ MonitorManager

Data type for the monitor manager.

◆ RNG

Data type of the shared RNG.

◆ Space

Data type of the space this model resides in.

◆ Time

Data type for the model time.

Constructor & Destructor Documentation

◆ Model()

template<class ParentModel , class... WriterArgs>
Utopia::Model< Derived, ModelTypes >::Model ( const std::string &  name,
const ParentModel< Derived, ModelTypes > &  parent_model,
const Config custom_cfg = {},
std::tuple< WriterArgs... >  w_args = {},
const DataIO::Default::DefaultDecidermap< Derived > &  w_deciders = DataIO::Default::default_decidersDerived >,
const DataIO::Default::DefaultTriggermap< Derived > &  w_triggers = DataIO::Default::default_triggersDerived > 
)
inline

Constructs a Model instance.

Uses information from a parent model to create a model instance.

Template Parameters
ParentModelThe parent model's type
Parameters
nameThe name of this model instance, ideally used only once on the current hierarchical level
parent_modelThe parent model object from which the corresponding config node, the group, the RNG, and the parent log level are extracted.
custom_cfgIf given, will use this configuration node instead of trying to extract one from the parent model's configuration.
w_argsPassed on to DataManager constructor. If not given, the DataManager will still be constructed. Take care to also set the WriteMode accordingly.
w_decidersMap which associates names with factory functions for deciders of signature factory()shared_ptr<Decider<Derived>>
w_triggersMap which associates names with factory functions for triggers of signature factory()shared_ptr<Trigger<Derived>>
273 {},
274 std::tuple< WriterArgs... > w_args = {},
275 const DataIO::Default::DefaultDecidermap< Derived >&
276 w_deciders = DataIO::Default::default_deciders< Derived >,
277 const DataIO::Default::DefaultTriggermap< Derived >&
278 w_triggers = DataIO::Default::default_triggers< Derived >
279 )
280 :
281 // First thing: setup name and position within model hierarchy
282 _name(name),
283 _full_name(parent_model.get_full_name() + "." + name),
285
286 // Retrieve the appropriate configuration entry from the parent model
287 _cfg(custom_cfg.size() ? custom_cfg
289
290 // Construct infrastructure objects using information from parent
293
294 // Determine space and time
296 _time(0),
298 : get_as<Time>("num_steps", _cfg,
299 std::numeric_limits<Time>::max())),
300
301 // Extract the other information from the parent model object
302 _hdfgrp(parent_model.get_hdfgrp()->open_group(_name)),
303 _write_start(get_as<Time>("write_start", _cfg,
305 _write_every(get_as<Time>("write_every", _cfg,
307
308 // Set up the monitor, using the parent model's monitor to place it in
309 // a hierarchy equivalent to the model hierarchy
311
312 // Default-construct the data maanger; only used if needed, see below.
314 {
315 // Provide some information, also depending on write mode
316 _log->info("Model base constructor for '{}' finished.", _name);
317 _log->info(" full_name: {}", _full_name);
318 _log->info(" level: {}", _level);
319 _log->info(" time_max: {:7d}", _time_max);
320
321 if constexpr (_write_mode == WriteMode::basic) {
322 _log->info(" write_mode: {:>7s}", "basic");
323 _log->info(" write_start: {:7d}", _write_start);
324 _log->info(" write_every: {:7d}", _write_every);
325 _log->info(" #writes: {:7d}", get_remaining_num_writes());
326
327 // Store relevant info in base group attributes
328 _hdfgrp->add_attribute("write_mode", "basic");
329 _hdfgrp->add_attribute("write_start", _write_start);
330 _hdfgrp->add_attribute("write_every", _write_every);
331 _hdfgrp->add_attribute("time_max", _time_max);
332 }
333 else if constexpr (_write_mode == WriteMode::manual) {
334 _log->info(" write_mode: {:>7s}", "manual");
335 _hdfgrp->add_attribute("write_mode", "manual");
336 }
337 else if constexpr (_write_mode == WriteMode::off) {
338 _log->info(" write_mode: {:>7s}", "off");
339 _hdfgrp->add_attribute("write_mode", "off");
340 }
341 else if constexpr (_write_mode == WriteMode::managed) {
342 static_assert(sizeof...(WriterArgs) > 0,
343 "No arguments to construct write_tasks given!");
344
345 _log->info(" write_mode: {:>7s}", "managed");
346
347 // Store relevant info in base group attributes
348 _hdfgrp->add_attribute("write_mode", "managed");
349
350 // Some convenience key checks for nicer error messages.
351 if (not _cfg["data_manager"]) {
352 throw KeyError("data_manager", _cfg,
353 "Cannot set up DataManager!");
354 }
355 const auto dm_cfg = _cfg["data_manager"];
356
357 if (not dm_cfg["tasks"]) {
358 throw KeyError("tasks", dm_cfg,
359 "Cannot set up DataManager tasks!");
360 }
361 if (not dm_cfg["deciders"]) {
362 throw KeyError("deciders", dm_cfg,
363 "Cannot set up DataManager deciders!");
364 }
365 if (not dm_cfg["triggers"]) {
366 throw KeyError("triggers", dm_cfg,
367 "Cannot set up DataManager triggers!");
368 }
369
370 _log->info("Invoking DataManager task factory ...");
371
372 _datamanager = DataIO::DataManagerFactory<Derived>()(
374 );
375
376 _log->info("DataManager set up with {} task(s), {} decider(s), "
377 "and {} trigger(s).", _datamanager.get_tasks().size(),
378 _datamanager.get_deciders().size(),
379 _datamanager.get_triggers().size());
380 }
381 }
TriggerMap & get_triggers()
Get the container of trigger objects.
Definition data_manager.hh:493
DeciderMap & get_deciders()
Get the container of decider objects.
Definition data_manager.hh:471
TaskMap & get_tasks()
Get the container of task objects.
Definition data_manager.hh:482
auto setup_logger(const Parent &parent_model) const
Constructs this models logger instance from the parent.
Definition model.hh:203
auto setup_space() const
Constructs the Space from configuration or uses the default Space.
Definition model.hh:225
const std::shared_ptr< DataGroup > _hdfgrp
The HDF group this model instance should write its data to.
Definition model.hh:176
DataManager _datamanager
Manager object for handling data output; see DataManager.
Definition model.hh:194
std::shared_ptr< DataGroup > get_hdfgrp() const
Return a pointer to the HDF group this model stores data in.
Definition model.hh:427
Monitor _monitor
The monitor.
Definition model.hh:188
Monitor get_monitor() const
Return the monitor of this model.
Definition model.hh:490
const Time _write_start
First time at which write_data is called.
Definition model.hh:182
Time get_time_max() const
Return the maximum time possible for this model.
Definition model.hh:403
const Config _cfg
Config node belonging to this model instance.
Definition model.hh:158
const Time _write_every
How often to call write_data from iterate.
Definition model.hh:185
Time _time
Model-internal current time stamp.
Definition model.hh:170
const std::string _name
Name of the model instance.
Definition model.hh:149
std::string get_full_name() const
Return the full name of this model within the model hierarchy.
Definition model.hh:422
const Time _time_max
Model-internal maximum time stamp.
Definition model.hh:173
hsize_t get_remaining_num_writes() const
Return the number of remaining write_data calls this model will make.
Definition model.hh:452
Config get_cfg() const
Return the config node of this model.
Definition model.hh:412
Time get_write_start() const
Return the parameter that controls when write_data is called first.
Definition model.hh:432
Level get_level() const
Return the hierarchical level within the model hierarchy.
Definition model.hh:500
const Level _level
The level within the model hierarchy.
Definition model.hh:155
typename ModelTypes::Time Time
Data type for the model time.
Definition model.hh:134
typename ModelTypes::Config Config
Data type that holds the configuration.
Definition model.hh:116
Time get_write_every() const
Return the parameter that controls how often write_data is called.
Definition model.hh:437
const std::string _full_name
The full name within the model hierarchy.
Definition model.hh:152
std::shared_ptr< RNG > get_rng() const
Return a pointer to the shared RNG.
Definition model.hh:480
const std::shared_ptr< spdlog::logger > _log
The (model) logger.
Definition model.hh:164
static constexpr WriteMode _write_mode
Which data-writing mode the base model should use.
Definition model.hh:179
const std::shared_ptr< RNG > _rng
The RNG shared between models.
Definition model.hh:161
std::shared_ptr< Space > _space
The space this model resides in.
Definition model.hh:167
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
@ off
The write_data method is never called.
@ manual
Fully manual: write_data method is always called.
@ managed
Use the DataManager to handle output.
@ basic
Basic writing features: write_start, write_every.
Definition parallel.hh:235

Member Function Documentation

◆ __attach_sig_handlers()

void Utopia::Model< Derived, ModelTypes >::__attach_sig_handlers ( ) const
inlineprivate

Attaches signal handlers: SIGINT, SIGTERM, SIGUSR1.

These signals are caught and handled such that the run method is able to finish in an ordered manner, preventing data corruption. This is done by invoking attach_signal_handler and attaching the default_signal_handler to them.

The SIGUSR1 signal is sent by the frontend if the stop conditions for this simulation are all fulfilled. It will likewise lead to the invocation of the default_signal_handler.

990 {
991 _log->debug("Attaching signal handlers for SIGINT and SIGTERM ...");
992
995
996 _log->debug("Attaching signal handler for stop conditions, triggered "
997 "by SIGUSR1 ({:d}) ...", SIGUSR1);
999
1000 _log->debug("Signal handlers attached.");
1001 }
void attach_signal_handler(int signum, Handler &&handler)
Attaches a signal handler for the given signal via sigaction.
Definition signal.hh:35

◆ __epilog()

void Utopia::Model< Derived, ModelTypes >::__epilog ( )
inlineprotected

The default epilog of a model.

Default tasks: None

705 {
706 this->_log->debug("Epilog finished.");
707 }

◆ __monitor()

void Utopia::Model< Derived, ModelTypes >::__monitor ( )
inlineprotected

Monitor information in the terminal.

642 {
643 if (_monitor.get_monitor_manager()->emit_enabled()) {
644 // Perform actions that should only happen once by the monitor at
645 // the highest level of the model hierarchy.
646 if (_level == 1){
647 // Supply the global time. When reaching this point, all sub-
648 // models will also have reached this time.
649 _monitor.get_monitor_manager()->set_time_entries(_time,
650 _time_max);
651 // This method also sets the other top level entries
652 }
653
654 // Call the child's implementation of the monitor functions.
655 impl().monitor();
656 }
657 }
Derived & impl()
cast to the derived class
Definition model.hh:712

◆ __perform_step()

void Utopia::Model< Derived, ModelTypes >::__perform_step ( )
inlineprotected

Perform the computation of a step.

633 {
634 impl().perform_step();
635 }

◆ __prolog()

void Utopia::Model< Derived, ModelTypes >::__prolog ( )
inlineprotected

The default prolog of a model.

Default tasks:

  1. call __write_initial_state
695 {
697
698 this->_log->debug("Prolog finished.");
699 }
void __write_initial_state()
Write the initial state.
Definition model.hh:666

◆ __write_data()

void Utopia::Model< Derived, ModelTypes >::__write_data ( )
inlineprotected

Write data; calls the implementation's write_data method.

660 {
661 _log->trace("Calling write_data ...");
662 impl().write_data();
663 }

◆ __write_initial_state()

void Utopia::Model< Derived, ModelTypes >::__write_initial_state ( )
inlineprotected

Write the initial state.

666 {
667 // Select the required WriteMode
668 // Decide on whether the initial state needs to be written
669 if constexpr (_write_mode == WriteMode::basic) {
670 if (_write_start == _time) {
671 _log->info("Writing initial state ...");
672 __write_data();
673 }
674 }
675 else if constexpr (_write_mode == WriteMode::manual) {
676 __write_data();
677 }
678 else if constexpr (_write_mode == WriteMode::managed) {
679 _datamanager(static_cast<Derived&>(*this));
680 }
681
682 }
void __write_data()
Write data; calls the implementation's write_data method.
Definition model.hh:660

◆ create_am_dset()

template<class AgentManager >
std::shared_ptr< DataSet > Utopia::Model< Derived, ModelTypes >::create_am_dset ( const std::string  name,
const AgentManager am,
const std::size_t  compression_level = 1,
const std::vector< hsize_t chunksize = {} 
)
inline

Create a dataset storing data from a AgentManager.

The required capacity - the shape of the dataset - is calculated using both data from the model and the AgentManager. Additionally, dimension and coordinate labels are added.

Agents are also labelled with a (trivial) ID, starting from zero.

Note
For the time dimension, the coordinates assume that data is written the first time at time 0 and then every _write_every. Time coordinates will be wrong if the model does not write the data this way. For such cases, it is advised to suppress writing of attributes by setting the config entry write_dim_labels_and_coords entry to false.
Warning
The number of agents present at the time this method is called determine the dataset's capacity. If the agent number increases beyond that point during the runtime of the simulation, data writing will fail because the datasets capacity will be too small!
Parameters
nameThe name of the dataset
amThe AgentManager whose agents' states are to be stored in the dataset
compression_levelThe compression level
chunksizeThe chunk size
Returns
std::shared_ptr<DataSet> The newly created HDFDataset
942 {})
943 {
944 // Forward to the main create_dset function
945 const auto dset = create_dset(
946 name,
947 _hdfgrp,
948 {am.agents().size()}, // --> 2D: time, agents
951 );
952
953 // Set attribute to store the agent managers' extent of space
954 dset->add_attribute("space_extent", am.space()->extent);
955 _log->debug("Added attribute to dataset '{}' to store space extent",
956 name);
957
958 // Write additional attributes, if not specifically suppressed.
959 if (get_as<bool>("write_dim_labels_and_coords", _cfg, true)) {
960 // We know that the dimensions here refer to (time, agent ids). The
961 // time information is already added in create_dset; add only ID
962 // information here. Note that this assumes trivial and constant
963 // agent IDs!
964 dset->add_attribute("dim_name__1", "ids");
965
966 // For ids, the dimensions are trivial
967 dset->add_attribute("coords_mode__ids", "trivial");
968
969 _log->debug("Added agent index dimension labels and coordinates "
970 "to dataset '{}'.", name);
971 }
972
973 return dset;
974 }
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

◆ create_cm_dset()

template<class CellManager >
std::shared_ptr< DataSet > Utopia::Model< Derived, ModelTypes >::create_cm_dset ( const std::string  name,
const CellManager cm,
const std::size_t  compression_level = 1,
const std::vector< hsize_t chunksize = {} 
)
inline

Create a dataset storing data from a CellManager.

The required capacity - the shape of the dataset - is calculated using both data from the model and the CellManager. Additionally, dimension and coordinate labels are added.

Note
For the time dimension, the coordinates assume that data is written the first time at time 0 and then every _write_every. Time coordinates will be wrong if the model does not write the data this way. For such cases, it is advised to suppress writing of attributes by setting the _cfg['write_dim_labels_and_coords'] entry to false.
Parameters
nameThe name of the dataset
cmThe CellManager whose cells' states are to be stored in the dataset
compression_levelThe compression level
chunksizeThe chunk size
Returns
std::shared_ptr<DataSet> The newly created HDFDataset
852 {})
853 {
854 // Forward to the main create_dset function
855 const auto dset = create_dset(
856 name,
857 _hdfgrp,
858 {cm.cells().size()}, // -> 2D dataset
861 );
862
863 // Set attributes to mark this dataset as containing grid data
864 dset->add_attribute("content", "grid");
865
866 // Need further attributes to denote the grid structure, size, etc.
867 const auto grid_structure = cm.grid()->structure_name();
868 dset->add_attribute("grid_structure", grid_structure);
869 dset->add_attribute("grid_shape", cm.grid()->shape());
870 dset->add_attribute("space_extent", cm.grid()->space()->extent);
871 dset->add_attribute("periodic_space", cm.grid()->space()->periodic);
872
873 if (grid_structure == "hexagonal") {
874 // ... some additional info is needed, which is dependent on the
875 // way the HexagonalGrid maps cells
876 dset->add_attribute("coordinate_mode", "offset");
877 dset->add_attribute("offset_mode", "even");
878 dset->add_attribute("pointy_top", true);
879 }
880
881 // The CellManager uses "column-style" index ordering, also called
882 // "Fortran-style". This is relevant for assigning the correct IDs.
883 dset->add_attribute("index_order", "F");
884
885 _log->debug("Added attributes to dataset '{}' to mark it as storing "
886 "grid data.", name);
887
888 // Write additional attributes, if not specifically suppressed.
889 if (get_as<bool>("write_dim_labels_and_coords", _cfg, true)) {
890 // We know that the dimensions here refer to (time, cell ids).
891 // The time information is already added in create_dset; only need
892 // to add the ID information here
893 dset->add_attribute("dim_name__1", "ids");
894
895 // For ids, the dimensions are trivial
896 dset->add_attribute("coords_mode__ids", "range");
897 dset->add_attribute("coords__ids",
898 std::vector<std::size_t>{cm.cells().size()});
899
900 _log->debug("Added cell ID dimension labels and coordinates to "
901 "dataset '{}'.", name);
902 }
903
904 return dset;
905 }

◆ create_dset() [1/2]

std::shared_ptr< DataSet > Utopia::Model< Derived, ModelTypes >::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 = {} 
)
inline

Create a new dataset within the given group.

The capacity - the shape of the dataset - is calculated automatically from the num_steps and write_every parameter. Additionally, dataset attributes are set that carry information on dimension labels and coordinates.

Note
The attributes are only written for the time dimension, as that is the only one that is known in this method. Furthermore, this assumes that it writes at write_every and - importantly - has the first write operation at time zero. Coordinates will be wrong if that is not the case! For such cases, it is advised to suppress writing of these attributes by setting the configuration entry _cfg['write_dim_labels_and_coords'] to false.
Parameters
nameThe name of the dataset
hdfgrpThe parent HDFGroup
add_write_shapeAdditional write shape which, together with the number of time steps, is used to calculate the capacity of the dataset: (capacity = (num_time_steps, add_write_shape)).
compression_levelThe compression level
chunksizeThe chunk size
Returns
std::shared_ptr<DataSet> The hdf dataset
756 {})
757 {
758 _log->debug("Creating dataset '{}' in group '{}' ...",
759 name, hdfgrp->get_path());
760
761 // Calculate the number of time steps to be written
763
764 // Calculate the shape of the dataset
766 auto capacity = add_write_shape;
767
768 // Create the dataset and return it.
769 const auto dset = hdfgrp->open_dataset(name, capacity,
771 _log->debug("Successfully created dataset '{}'.", name);
772
773 // Write further attributes, if not specifically suppressed
774 if (get_as<bool>("write_dim_labels_and_coords", _cfg, true)) {
775 // We know that dimension 0 is the time dimension. Add the
776 // attributes that specify dimension names and coordinates:
777 dset->add_attribute("dim_name__0", "time");
778 dset->add_attribute("coords_mode__time", "start_and_step");
779 dset->add_attribute("coords__time",
780 std::vector<std::size_t>{_write_start,
781 _write_every});
782 _log->debug("Added time dimension labels and coordinates to "
783 "dataset '{}'.", name);
784 }
785
786 return dset;
787 }

◆ create_dset() [2/2]

std::shared_ptr< DataSet > Utopia::Model< Derived, ModelTypes >::create_dset ( const std::string  name,
const std::vector< hsize_t add_write_shape,
const std::size_t  compression_level = 1,
const std::vector< hsize_t chunksize = {} 
)
inline

Create a new dataset within the model's base data group.

The capacity - the shape of the dataset - is calculated automatically from the num_steps and write_every parameter. Additionally, dataset attributes are set that carry information on dimension labels and coordinates.

Note
The attributes are only written for the time dimension, as that is the only one that is known in this method. Furthermore, this assumes that it writes at write_every and - importantly - has the first write operation at time zero. Coordinates will be wrong if that is not the case! For such cases, it is advised to suppress writing of these attributes by setting the configuration entry _cfg['write_dim_labels_and_coords'] to false.
Parameters
nameThe name of the dataset
add_write_shapeAdditional write shape which, together with the number of time steps, is used to calculate the capacity of the dataset: (capacity = (num_time_steps, add_write_shape)).
compression_levelThe compression level
chunksizeThe chunk size
Returns
std::shared_ptr<DataSet> The hdf dataset
818 {})
819 {
820 // Forward to the main create_dset function
821 return create_dset(name,
822 _hdfgrp, // The base group for this model
824 }

◆ epilog()

virtual void Utopia::Model< Derived, ModelTypes >::epilog ( )
inlinevirtual

A function that is called after the last iteration of a model.

See __epilog() for default tasks

516 {
517 __epilog();
518 }
void __epilog()
The default epilog of a model.
Definition model.hh:705

◆ get_cfg()

Config Utopia::Model< Derived, ModelTypes >::get_cfg ( ) const
inline

Return the config node of this model.

412 {
413 return _cfg;
414 }

◆ get_datamanager()

DataManager Utopia::Model< Derived, ModelTypes >::get_datamanager ( ) const
inline

return the datamanager

442 {
443 return _datamanager;
444 }

◆ get_full_name()

std::string Utopia::Model< Derived, ModelTypes >::get_full_name ( ) const
inline

Return the full name of this model within the model hierarchy.

422 {
423 return _full_name;
424 }

◆ get_hdfgrp()

std::shared_ptr< DataGroup > Utopia::Model< Derived, ModelTypes >::get_hdfgrp ( ) const
inline

Return a pointer to the HDF group this model stores data in.

427 {
428 return _hdfgrp;
429 }

◆ get_level()

Level Utopia::Model< Derived, ModelTypes >::get_level ( ) const
inline

Return the hierarchical level within the model hierarchy.

500 {
501 return _level;
502 }

◆ get_logger()

std::shared_ptr< spdlog::logger > Utopia::Model< Derived, ModelTypes >::get_logger ( ) const
inline

Return a pointer to the logger of this model.

485 {
486 return _log;
487 }

◆ get_monitor()

Monitor Utopia::Model< Derived, ModelTypes >::get_monitor ( ) const
inline

Return the monitor of this model.

490 {
491 return _monitor;
492 }

◆ get_monitor_manager()

std::shared_ptr< MonitorManager > Utopia::Model< Derived, ModelTypes >::get_monitor_manager ( ) const
inline

Get the monitor manager of the root model.

495 {
496 return _monitor.get_monitor_manager();
497 }

◆ get_name()

std::string Utopia::Model< Derived, ModelTypes >::get_name ( ) const
inline

Return the name of this model instance.

417 {
418 return _name;
419 }

◆ get_remaining_num_writes()

hsize_t Utopia::Model< Derived, ModelTypes >::get_remaining_num_writes ( ) const
inline

Return the number of remaining write_data calls this model will make.

The 'remaining' refers to the current time being included into the calculation, e.g.: when writing every time, currently at time == 42 and time_max == 43, it will return the value 2, i.e. for the write operations at times 42 and 43

452 {
453 static_assert(
458 );
459
460 if constexpr (_write_mode == WriteMode::basic) {
461 if (_time_max == std::numeric_limits<hsize_t>::max()) {
462 return std::numeric_limits<hsize_t>::max();
463 }
464 return ( (_time_max - std::max(_time, _write_start))
465 / _write_every) + 1;
466 }
467 else if constexpr (_write_mode == WriteMode::manual) {
468 if (_time_max - _time == std::numeric_limits<hsize_t>::max()) {
469 return std::numeric_limits<hsize_t>::max();
470 }
471 return _time_max - _time + 1;
472 }
473 else {
474 return 0;
475 }
476
477 }

◆ get_rng()

std::shared_ptr< RNG > Utopia::Model< Derived, ModelTypes >::get_rng ( ) const
inline

Return a pointer to the shared RNG.

480 {
481 return _rng;
482 }

◆ get_space()

const std::shared_ptr< Space > & Utopia::Model< Derived, ModelTypes >::get_space ( ) const
inline

Return the space this model resides in.

388 {
389 return _space;
390 }

◆ get_time()

Time Utopia::Model< Derived, ModelTypes >::get_time ( ) const
inline

Return the current time of this model.

393 {
394 return _time;
395 }

◆ get_time_max()

Time Utopia::Model< Derived, ModelTypes >::get_time_max ( ) const
inline

Return the maximum time possible for this model.

Note
Will emit a warning via the logger if the this was set to the maximum possible value, e.g. because this model is run as a submodel of another model and the maximum time has no relevance in such a context.
403 {
404 if (_time_max == std::numeric_limits<Time>::max()) {
405 this->_log->warn("Accessing the `time_max` of (sub-)model {} with "
406 "unlimited value!", this->get_full_name());
407 }
408 return _time_max;
409 }

◆ get_write_every()

Time Utopia::Model< Derived, ModelTypes >::get_write_every ( ) const
inline

Return the parameter that controls how often write_data is called.

437 {
438 return _write_every;
439 }

◆ get_write_start()

Time Utopia::Model< Derived, ModelTypes >::get_write_start ( ) const
inline

Return the parameter that controls when write_data is called first.

432 {
433 return _write_start;
434 }

◆ impl() [1/2]

Derived & Utopia::Model< Derived, ModelTypes >::impl ( )
inlineprotected

cast to the derived class

712 {
713 return static_cast<Derived&>(*this);
714 }

◆ impl() [2/2]

const Derived & Utopia::Model< Derived, ModelTypes >::impl ( ) const
inlineprotected

const cast to the derived interface

717 {
718 return static_cast<const Derived&>(*this);
719 }

◆ increment_time()

void Utopia::Model< Derived, ModelTypes >::increment_time ( const Time  dt = 1)
inlineprotected

Increment time.

Parameters
dtTime increment, defaults to 1
687 {
688 _time += dt;
689 }

◆ iterate()

void Utopia::Model< Derived, ModelTypes >::iterate ( )
inline

Iterate one (time) step of this model.

Increment time, perform step, emit monitor data, and write data. Monitoring is performed differently depending on the model level. The write_data method is called depending on the configured value for the write_mode (template parameter) and (if in mode basic): the configuration parameters write_start and write_every.

527 {
528 // -- Perform the simulation step
531
532 // -- Monitoring
533 /* If the model is at the first hierarchical level, check whether the
534 * monitor entries should be collected and emitted. This leads to a
535 * flag being set in the monitor manager, such that the submodels do
536 * not have to do the check against the timer as well and that all
537 * collected data stems from the same time step.
538 */
539 if (_level == 1) {
540 _monitor.get_monitor_manager()->check_timer();
541 __monitor();
542
543 // If enabled for this step, perform the emission of monitor data
544 // NOTE At this point, we can be sure that all submodels have
545 // already run, because their iterate functions were called
546 // in the perform_step of the level 1 model.
547 _monitor.get_monitor_manager()->emit_if_enabled();
548 }
549 else {
550 __monitor();
551 }
552
553 // -- Data output
554 if constexpr (_write_mode == WriteMode::basic) {
555 if ( (_time >= _write_start)
556 and (_time - _write_start) % _write_every == 0) {
557 __write_data();
558 }
559 }
560 else if constexpr (_write_mode == WriteMode::manual) {
561 __write_data();
562 }
563 else if constexpr (_write_mode == WriteMode::managed) {
564 _datamanager(static_cast<Derived&>(*this));
565 }
566
567 if (_level == 1) {
568 _log->debug("Finished iteration: {:7d} / {:d}", _time, _time_max);
569 }
570 else {
571 _log->debug("Finished iteration: {:7d}", _time);
572 }
573 }
void __monitor()
Monitor information in the terminal.
Definition model.hh:642
void __perform_step()
Perform the computation of a step.
Definition model.hh:633
void increment_time(const Time dt=1)
Increment time.
Definition model.hh:687

◆ prolog()

virtual void Utopia::Model< Derived, ModelTypes >::prolog ( )
inlinevirtual

A function that is called before starting model iteration.

See __prolog() for default tasks

509 {
510 __prolog();
511 }
void __prolog()
The default prolog of a model.
Definition model.hh:695

◆ run()

Run the model from the current time to the maximum time.

This repeatedly calls the iterate method until the maximum time is reached. Additionally, it calls the __write_data method to allow it to write the initial state. In write mode basic, this is only done if _write_start == _time.

581 {
582 if (_level > 1 and get_time_max() == std::numeric_limits<Time>::max()) {
583 throw std::runtime_error(fmt::format("Cannot perform run on "
584 "(sub-)model {} with unlimited `time_max`. You need to provide "
585 "`num_steps` to the model's configuration in order to use the "
586 "`run` method. See the nested models guide for further "
587 "information!", get_full_name()));
588 }
589
590 // First, attach the signal handler, such that the while loop below can
591 // be left upon receiving of a signal.
593
594 // call the prolog of the model
595 prolog();
596
597 // Now, let's go repeatedly iterate the model ...
598 _log->info("Running from current time {} to {} ...",
600
601 while (_time < _time_max) {
602 iterate();
603
604 if (stop_now.load()) {
605 const auto signum = received_signum.load();
606
607 if (signum == SIGUSR1) {
608 _log->warn("The stop condition for this run is fulfilled. "
609 "Not iterating further ...");
610 }
611 else {
612 _log->warn("Was told to stop. Not iterating further ...");
613 }
614
615 _log->info("Invoking epilog ...");
616 epilog();
617
618 throw GotSignal(received_signum.load());
619 }
620 }
621
622 _log->info("Run finished. Current time: {}", _time);
623
624 // call the epilog of the model
625 epilog();
626 }
void iterate()
Iterate one (time) step of this model.
Definition model.hh:527
void __attach_sig_handlers() const
Attaches signal handlers: SIGINT, SIGTERM, SIGUSR1.
Definition model.hh:990
virtual void epilog()
A function that is called after the last iteration of a model.
Definition model.hh:516
virtual void prolog()
A function that is called before starting model iteration.
Definition model.hh:509
std::atomic< bool > stop_now
The flag indicating whether to stop whatever is being done right now.
Definition signal.hh:15
std::atomic< int > received_signum
The received signal value.
Definition signal.hh:18

◆ setup_logger()

template<class Parent >
auto Utopia::Model< Derived, ModelTypes >::setup_logger ( const Parent parent_model) const
inlineprivate

Constructs this models logger instance from the parent.

Also directly sets the log level from the log_level config entry.

203 {
204 auto log = spdlog::stdout_color_mt(
205 parent_model.get_logger()->name() + "." + _name
206 );
207
208 // Set this model instance's log level
209 if (_cfg["log_level"]) {
210 // Via value given in configuration
211 const auto lvl = get_as<std::string>("log_level", _cfg);
212 log->debug("Setting log level to '{}' ...", lvl);
213 log->set_level(spdlog::level::from_str(lvl));
214 }
215 else {
216 // No config value given; use the level of the parent's logger
217 log->set_level(parent_model.get_logger()->level());
218 }
219
220 log->info("Model logger initialized.");
221 return log;
222 }

◆ setup_space()

auto Utopia::Model< Derived, ModelTypes >::setup_space ( ) const
inlineprivate

Constructs the Space from configuration or uses the default Space.

225 {
226 if (_cfg["space"]) {
227 auto space = std::make_shared<Space>(_cfg["space"]);
228 _log->info(
229 "Using {}periodic space with extent {}.",
230 space->periodic ? "" : "non-", Utils::str(space->extent)
231 );
232 return space;
233 }
234 else {
235 _log->debug(
236 "No model-level space configured; using default space."
237 );
238 return std::make_shared<Space>();
239 }
240 }
std::string str(T &&t)
Turn any object for which operator<< exists into a string. Mostly useful for logging data via spdlog ...
Definition ostream.hh:164

Member Data Documentation

◆ _cfg

Config node belonging to this model instance.

◆ _datamanager

DataManager Utopia::Model< Derived, ModelTypes >::_datamanager
protected

Manager object for handling data output; see DataManager.

Note
The data manager is always constructed, but only used if the _write_mode was set to WriteMode::managed.

◆ _full_name

const std::string Utopia::Model< Derived, ModelTypes >::_full_name
protected

The full name within the model hierarchy.

◆ _hdfgrp

const std::shared_ptr<DataGroup> Utopia::Model< Derived, ModelTypes >::_hdfgrp
protected

The HDF group this model instance should write its data to.

◆ _level

The level within the model hierarchy.

◆ _log

const std::shared_ptr<spdlog::logger> Utopia::Model< Derived, ModelTypes >::_log
protected

The (model) logger.

◆ _monitor

Monitor Utopia::Model< Derived, ModelTypes >::_monitor
protected

The monitor.

◆ _name

const std::string Utopia::Model< Derived, ModelTypes >::_name
protected

Name of the model instance.

◆ _rng

const std::shared_ptr<RNG> Utopia::Model< Derived, ModelTypes >::_rng
protected

The RNG shared between models.

◆ _space

std::shared_ptr<Space> Utopia::Model< Derived, ModelTypes >::_space
protected

The space this model resides in.

◆ _time

Time Utopia::Model< Derived, ModelTypes >::_time
protected

Model-internal current time stamp.

◆ _time_max

const Time Utopia::Model< Derived, ModelTypes >::_time_max
protected

Model-internal maximum time stamp.

◆ _write_every

const Time Utopia::Model< Derived, ModelTypes >::_write_every
protected

How often to call write_data from iterate.

◆ _write_mode

constexpr WriteMode Utopia::Model< Derived, ModelTypes >::_write_mode = ModelTypes::write_mode
staticconstexprprotected

Which data-writing mode the base model should use.

◆ _write_start

const Time Utopia::Model< Derived, ModelTypes >::_write_start
protected

First time at which write_data is called.


The documentation for this class was generated from the following file: