-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmodule_helper_functions.cpp
More file actions
200 lines (181 loc) · 6.54 KB
/
module_helper_functions.cpp
File metadata and controls
200 lines (181 loc) · 6.54 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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#include "module_helper_functions.h"
#include <cmath> // For log10
#include <sstream> // For replicating old sprintf functionality with strings
#include <iomanip> // For replicating old sprintf functionality with strings
/**
* @brief Returns a pointer to an element of a module output map, i.e., an
* output pointer (op)
*/
double* get_op(state_map* output_quantities, const std::string& name)
{
if (output_quantities->find(name) == output_quantities->end()) {
throw quantity_access_error(
std::string("Thrown by get_op: the quantity '") + name +
std::string("' was not defined in the state_map."));
}
return &(output_quantities->at(name));
}
/**
* @brief Returns a vector of pointers to elements of a module output map, i.e.,
* a vector of output pointers (op)
*/
std::vector<double*> get_op(
state_map* output_quantities, string_vector const& names)
{
std::vector<double*> ops;
for (std::string const& n : names) {
ops.push_back(get_op(output_quantities, n));
}
return ops;
}
/**
* @brief Returns a pointer to an element of a module input map, i.e., an input
* pointer (ip)
*/
const double* get_ip(state_map const& input_quantities, const std::string& name)
{
if (input_quantities.find(name) == input_quantities.end()) {
throw quantity_access_error(
std::string("Thrown by get_ip: the quantity '") + name +
std::string("' was not defined in the state_map."));
}
return &(input_quantities.at(name));
}
/**
* @brief Returns a vector of pointers to elements of a module input map, i.e.,
* a vector of input pointers (ip)
*/
std::vector<const double*> get_ip(
state_map const& input_quantities, string_vector const& names)
{
std::vector<const double*> ips;
for (std::string const& n : names) {
ips.push_back(get_ip(input_quantities, n));
}
return ips;
}
/**
* @brief Returns a reference to an element of a module input map
*/
double const& get_input(
state_map const& input_quantities, const std::string& name)
{
if (input_quantities.find(name) == input_quantities.end()) {
throw quantity_access_error(
std::string("Thrown by get_input: the quantity '") + name +
std::string("' was not defined in the state_map."));
}
return input_quantities.at(name);
}
/**
* @brief Adds a class name prefix to the quantity name indicating it was
* calculated for a certain leaf class, e.g. sunlit or shaded.
*/
std::string add_class_prefix_to_quantity_name(
std::string class_name, std::string quantity_name)
{
return class_name + std::string("_") + quantity_name;
}
/**
* @brief Adds class name prefixes to each quantity name indicating that it was
* calculated for a certain class. E.g., a multilayer canopy model may calculate
* different incident light irradiance values for sunlit and shaded leaves. In
* this case, "sunlit" and "shaded" would be the two leaf classes.
*/
string_vector generate_multiclass_quantity_names(
string_vector class_names, string_vector quantity_names)
{
string_vector full_multiclass_output_vector;
for (std::string const& cn : class_names) {
for (std::string const& qn : quantity_names) {
full_multiclass_output_vector.push_back(
add_class_prefix_to_quantity_name(cn, qn));
}
}
return full_multiclass_output_vector;
}
/**
* @brief Adds a suffix to a quantity name indicating that it was calculated for
* a certain layer.
*/
std::string add_layer_suffix_to_quantity_name(
int nlayers, int current_layer, std::string quantity_name)
{
std::stringstream param_name_stream;
// Get the number of digits in the largest layer number
int num_digits = ceil(log10(nlayers - 1.0));
// Add the suffix
param_name_stream << quantity_name
<< "_layer_"
<< std::setfill('0')
<< std::setw(num_digits)
<< current_layer;
return param_name_stream.str();
}
/**
* @brief For each entry in the `quantity_names` vector, multiple copies are
* produced, each of which has a suffix indicating the corresponding layer.
*/
string_vector generate_multilayer_quantity_names(
int nlayers, string_vector quantity_names)
{
string_vector full_multilayer_output_vector;
for (size_t i = 0; i < quantity_names.size(); i++) {
for (int j = 0; j < nlayers; j++) {
full_multilayer_output_vector.push_back(
add_layer_suffix_to_quantity_name(
nlayers, j, quantity_names[i]));
}
}
return full_multilayer_output_vector;
}
/**
* @brief Analagous to `get_op` but returns a vector of output pointers, as
* required for a multilayer module
*/
std::vector<double*> get_multilayer_op(
state_map* output_quantities, int nlayers, std::string const& name)
{
string_vector quantity_base_name_vector = {name};
string_vector quantity_names =
generate_multilayer_quantity_names(nlayers, quantity_base_name_vector);
std::vector<double*> multilayer_pointers(nlayers);
for (int i = 0; i < nlayers; i++) {
multilayer_pointers[i] = get_op(output_quantities, quantity_names[i]);
}
return multilayer_pointers;
}
/**
* @brief Analagous to `get_ip` but returns a vector of output pointers, as
* required for a multilayer module
*/
std::vector<const double*> get_multilayer_ip(
state_map const& input_quantities, int nlayers, std::string const& name)
{
string_vector quantity_base_name_vector = {name};
string_vector quantity_names = generate_multilayer_quantity_names(
nlayers, quantity_base_name_vector);
std::vector<const double*> multilayer_pointers(nlayers);
for (int i = 0; i < nlayers; i++) {
multilayer_pointers[i] = get_ip(input_quantities, quantity_names[i]);
}
return multilayer_pointers;
}
/**
* @brief Checks over an `error_map` for problems. The `error_map` should pair a
* string description of an important criterion which must be met, e.g.
* "Parameter_A must be non-zero", with a boolean indicating whether it has been
* met. If the condition was not met, an appropriate error message will be
* generated indicating both the problem and the module in which it occurred.
*/
void check_error_conditions(
std::map<std::string, bool> errors_to_check, std::string module_name)
{
for (auto const& x : errors_to_check) {
if (x.second) {
throw std::out_of_range(
std::string("Thrown by the '") + module_name +
std::string("' module: ") + x.first);
}
}
}