-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmodule.h
More file actions
173 lines (151 loc) · 5.16 KB
/
module.h
File metadata and controls
173 lines (151 loc) · 5.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#ifndef MODULE_H
#define MODULE_H
#include <vector>
#include <memory> // For std::unique_ptr
#include "module_helper_functions.h" // Essential for all modules
/**
* @class module
*
* @brief Represents one or more equations
*
* This class defines the operational interface to all module classes.
*
* The central feature of a module is its `run()` method, which should retrieve
* values of its input quantities, perform calculations, and update the values
* of its outputs. These operations are achieved in the `do_operation()` method
* of a concrete derived class using pointers; upon construction, a module
* should store references (or pointers) to its input quantities and pointers
* to its output quantities. Input and output quantities alike are stored as
* elements of `state_map` objects which are passed by reference to module
* constructors.
*
* A module can be one of the following subtypes:
*
* - `direct_module`: directly calculates the instantaneous value(s) of one or
* more quantities
*
* - `differential_module`: a module that calculates the instantaneous rate(s)
* of change for one or more quantities
*
* A module must also indicate whether or not it requires an Euler
* `ode_solver`. Most modules do not. However, a few "legacy" modules require
* information from previous times and will only work properly with a fixed
* step size Euler ODE solver.
*
* Typically, concrete classes derived from this one are not instantiated
* directly; instead, module objects are created by `module_creator` objects
* retrieved from the `module_factory`.
*/
class module
{
public:
module(
bool const& differential,
bool const& requires_euler)
: differential{differential},
requires_euler{requires_euler}
{
}
virtual ~module() = 0;
// Functions for returning module information
bool is_differential() const { return differential; }
bool requires_euler_ode_solver() const { return requires_euler; }
// Functions for running the module
void run() const { do_operation(); }
private:
virtual void do_operation() const = 0;
std::string const module_name;
bool const differential;
bool const requires_euler;
protected:
// Updates the values of output quantities
virtual void update(double* output_ptr, const double& value) const = 0;
};
/**
* @brief A destructor must be defined, and since the default is overridden
* when defining it as pure virtual, add an inline one in the header
*/
inline module::~module() {}
/**
* @class direct_module
*
* @brief This class represents a direct module.
*
* This class has a pure virtual destructor to designate it as being
* intentionally abstract.
*/
class direct_module : public module
{
public:
direct_module(bool requires_euler = false)
: module{false, requires_euler}
{
}
virtual ~direct_module() = 0;
protected:
void update(double* output_ptr, const double& value) const;
};
/**
* @brief A destructor must be defined, and since the default is overridden
* when defining it as pure virtual, add an inline one in the header
*/
inline direct_module::~direct_module() {}
/**
* @brief In a valid `dynamical_system` object, a given quantity may be defined
* by only one direct module. Thus the value at `output_ptr` will only
* be writable from a single module, and we can overwrite any previously
* stored value.
*
* See `differential_module::update()` for a contrasting situation.
*/
inline void direct_module::update(double* output_ptr, const double& value) const
{
*output_ptr = value;
}
/**
* @class differential_module
*
* @brief This class represents a differential module.
*
* This class has a pure virtual destructor to designate it as being
* intentionally abstract.
*/
class differential_module : public module
{
public:
differential_module(bool requires_euler = false)
: module{true, requires_euler}
{
}
virtual ~differential_module() = 0;
protected:
void update(double* output_ptr, const double& value) const;
};
/**
* @brief A destructor must be defined, and since the default is overridden
* when defining it as pure virtual, add an inline one in the header
*/
inline differential_module::~differential_module() {}
/**
* @brief The outputs of a differential module represent additive terms in the
* derivatives of its output quantities, and, in a valid
* `dynamical_system` object, it is possible for one derivative to be
* determined by more than one module; for this reason, the output
* values should be added to the previously stored values.
*
* See `direct_module::update()` for a contrasting situation.
*/
inline void differential_module::update(double* output_ptr, const double& value) const
{
*output_ptr += value;
}
/**
* @brief `module_vector` serves as an alias for a type widely used to
* hold lists of modules.
*
* Formally, it is a `std::vector` of `std::unique_ptr`s that point to
* `module` objects.
*/
using module_vector = std::vector<std::unique_ptr<module>>;
void run_module_list(module_vector const& modules);
#endif