Line data Source code
1 : // rbOOmit: An implementation of the Certified Reduced Basis method.
2 : // Copyright (C) 2009, 2010 David J. Knezevic
3 :
4 : // This file is part of rbOOmit.
5 :
6 : // rbOOmit is free software; you can redistribute it and/or
7 : // modify it under the terms of the GNU Lesser General Public
8 : // License as published by the Free Software Foundation; either
9 : // version 2.1 of the License, or (at your option) any later version.
10 :
11 : // rbOOmit is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : // Lesser General Public License for more details.
15 :
16 : // You should have received a copy of the GNU Lesser General Public
17 : // License along with this library; if not, write to the Free Software
18 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 :
20 : // libmesh includes
21 : #include "libmesh/int_range.h"
22 : #include "libmesh/libmesh_common.h"
23 : #include "libmesh/rb_parameters.h"
24 : #include "libmesh/utility.h"
25 :
26 : // C++ includes
27 : #include <algorithm>
28 : #include <sstream>
29 :
30 : namespace libMesh
31 : {
32 :
33 414081 : RBParameters::RBParameters() :
34 414081 : _n_samples(1)
35 : {
36 414081 : }
37 :
38 71 : RBParameters::RBParameters(const std::map<std::string, Real> & parameter_map) :
39 71 : _n_samples(1)
40 : {
41 : // Backwards compatible support for constructing an RBParameters
42 : // object from a map<string, Real>. We store a single entry in each
43 : // vector in the map.
44 284 : for (const auto & [key, val] : parameter_map)
45 432 : _parameters[key] = {{val}};
46 473 : }
47 :
48 0 : void RBParameters::clear()
49 : {
50 0 : _n_samples = 1;
51 0 : _parameters.clear();
52 0 : _extra_parameters.clear();
53 0 : }
54 :
55 497 : bool RBParameters::has_value(const std::string & param_name) const
56 : {
57 497 : return _parameters.count(param_name);
58 : }
59 :
60 71 : bool RBParameters::has_extra_value(const std::string & param_name) const
61 : {
62 71 : return _extra_parameters.count(param_name);
63 : }
64 :
65 34318474 : Real RBParameters::get_value(const std::string & param_name) const
66 : {
67 : // Simply return the [0]th entry of the vector if possible, otherwise error.
68 34318750 : libmesh_error_msg_if(this->n_samples() != 1,
69 : "Requesting value for parameter " << param_name << ", but parameter contains multiple samples.");
70 34318332 : return this->get_sample_value(param_name, /*sample_idx=*/0);
71 : }
72 :
73 0 : const RBParameter& RBParameters::get_vector_value(const std::string & param_name) const
74 : {
75 : // Simply return the [0]th entry of the vector if possible, otherwise error.
76 0 : libmesh_error_msg_if(this->n_samples() != 1,
77 : "Requesting value for parameter " << param_name << ", but parameter contains multiple sample.");
78 0 : return this->get_sample_vector_value(param_name, /*sample_idx=*/0);
79 : }
80 :
81 142 : Real RBParameters::get_value(const std::string & param_name, const Real & default_val) const
82 : {
83 : // Simply return the [0]th entry of the vector if possible, otherwise error.
84 418 : libmesh_error_msg_if(this->n_samples() != 1,
85 : "Requesting value for parameter " << param_name << ", but parameter contains multiple samples.");
86 0 : return this->get_sample_value(param_name, /*sample_idx=*/0, default_val);
87 : }
88 :
89 0 : const RBParameter & RBParameters::get_vector_value(const std::string & param_name, const RBParameter & default_val) const
90 : {
91 : // Simply return the [0]th entry of the vector if possible, otherwise error.
92 0 : libmesh_error_msg_if(this->n_samples() != 1,
93 : "Requesting value for parameter " << param_name << ", but parameter contains multiple samples.");
94 0 : return this->get_sample_vector_value(param_name, /*sample_idx=*/0, default_val);
95 : }
96 :
97 34319113 : Real RBParameters::get_sample_value(const std::string & param_name, std::size_t sample_idx) const
98 : {
99 34319113 : const auto & sample_vec = libmesh_map_find(_parameters, param_name);
100 37129457 : libmesh_error_msg_if(sample_idx >= sample_vec.size(), "Error getting value for parameter " << param_name);
101 37129173 : libmesh_error_msg_if(sample_vec[sample_idx].size() != 1,
102 : "Requesting Real value for parameter " << param_name << ", but parameter contains multiple values.");
103 34318758 : return sample_vec[sample_idx][0];
104 : }
105 :
106 284 : const RBParameter & RBParameters::get_sample_vector_value(const std::string & param_name, std::size_t sample_idx) const
107 : {
108 284 : const auto & sample_vec = libmesh_map_find(_parameters, param_name);
109 357 : libmesh_error_msg_if(sample_idx >= sample_vec.size(), "Error getting value for parameter " << param_name);
110 142 : return sample_vec[sample_idx];
111 : }
112 :
113 213 : Real RBParameters::get_sample_value(const std::string & param_name, std::size_t sample_idx, const Real & default_val) const
114 : {
115 6 : auto it = _parameters.find(param_name);
116 213 : if (it == _parameters.end() || sample_idx >= it->second.size())
117 213 : return default_val;
118 0 : libmesh_error_msg_if(it->second[sample_idx].size() != 1,
119 : "Requesting Real value for parameter " << param_name << ", but parameter contains multiple values.");
120 0 : return it->second[sample_idx][0];
121 : }
122 :
123 71 : const RBParameter & RBParameters::get_sample_vector_value(const std::string & param_name, std::size_t sample_idx, const RBParameter & default_val) const
124 : {
125 2 : auto it = _parameters.find(param_name);
126 71 : if (it == _parameters.end() || sample_idx >= it->second.size())
127 2 : return default_val;
128 0 : return it->second[sample_idx];
129 : }
130 :
131 7067 : void RBParameters::set_value(const std::string & param_name, Real value)
132 : {
133 : // This version of set_value() does not take an index and is provided
134 : // for backwards compatibility. It creates a vector entry for the specified
135 : // param_name, overwriting any value(s) that were present.
136 21003 : _parameters[param_name] = {{value}};
137 13738 : }
138 :
139 2619682 : void RBParameters::set_value(const std::string & param_name, const RBParameter & value)
140 : {
141 : // This version of set_value() does not take an index and is provided
142 : // for backwards compatibility. It creates a vector entry for the specified
143 : // param_name, overwriting any value(s) that were present.
144 7640756 : _parameters[param_name] = {value};
145 4802784 : }
146 :
147 : void
148 21799 : RBParameters::set_value_helper(std::map<std::string, std::vector<RBParameter>> & map,
149 : const std::string & param_name,
150 : const std::size_t index,
151 : RBParameter value)
152 : {
153 : // Get reference to vector of values for this parameter, creating it
154 : // if it does not already exist.
155 21799 : auto & sample_vec = map[param_name];
156 :
157 : // If vec is already big enough, just set the value
158 22413 : if (sample_vec.size() > index)
159 586 : sample_vec[index] = std::move(value);
160 :
161 : // Otherwise push_back() if the vec is just barely not big enough
162 994 : else if (sample_vec.size() == index)
163 497 : sample_vec.emplace_back(std::move(value));
164 :
165 : // Otherwise, allocate more space (padding with 0s) if vector is not
166 : // big enough to fit the user's requested index.
167 : else
168 : {
169 525 : RBParameter zero_parameter(value.size(), 0.0);
170 497 : sample_vec.resize(index+1, zero_parameter);
171 28 : sample_vec[index] = std::move(value);
172 : }
173 21799 : }
174 :
175 923 : void RBParameters::set_value(const std::string & param_name, std::size_t index, Real value)
176 : {
177 923 : this->set_value_helper(_parameters, param_name, index, {value});
178 923 : }
179 :
180 20876 : void RBParameters::set_value(const std::string & param_name, std::size_t index, const RBParameter & value)
181 : {
182 20876 : this->set_value_helper(_parameters, param_name, index, value);
183 20876 : }
184 :
185 0 : void RBParameters::set_extra_value(const std::string & param_name, std::size_t index, Real value)
186 : {
187 0 : this->set_value_helper(_extra_parameters, param_name, index, {value});
188 0 : }
189 :
190 0 : void RBParameters::set_extra_value(const std::string & param_name, std::size_t index, const RBParameter & value)
191 : {
192 0 : this->set_value_helper(_extra_parameters, param_name, index, value);
193 0 : }
194 :
195 710 : void RBParameters::push_back_value(const std::string & param_name, Real value)
196 : {
197 : // Get reference to vector of values for this parameter, creating it
198 : // if it does not already exist, and push back the specified value.
199 710 : _parameters[param_name].push_back({value});
200 710 : }
201 :
202 142 : void RBParameters::push_back_value(const std::string & param_name, const RBParameter & value)
203 : {
204 : // Get reference to vector of values for this parameter, creating it
205 : // if it does not already exist, and push back the specified value.
206 142 : _parameters[param_name].push_back(value);
207 142 : }
208 :
209 213 : void RBParameters::push_back_extra_value(const std::string & param_name, Real value)
210 : {
211 : // Get reference to vector of values for this extra parameter, creating it
212 : // if it does not already exist, and push back the specified value.
213 213 : _extra_parameters[param_name].push_back({value});
214 213 : }
215 :
216 0 : void RBParameters::push_back_extra_value(const std::string & param_name, const RBParameter & value)
217 : {
218 : // Get reference to vector of values for this extra parameter, creating it
219 : // if it does not already exist, and push back the specified value.
220 0 : _extra_parameters[param_name].push_back(value);
221 0 : }
222 :
223 0 : Real RBParameters::get_extra_value(const std::string & param_name) const
224 : {
225 : // Same as get_value(param_name) but for the map of extra parameters
226 0 : const auto & sample_vec = libmesh_map_find(_extra_parameters, param_name);
227 0 : libmesh_error_msg_if(sample_vec.size() != 1,
228 : "Requesting value for extra parameter " << param_name << ", but parameter contains multiple samples.");
229 0 : libmesh_error_msg_if(sample_vec[0].size() != 1,
230 : "Requesting Real value for extra parameter " << param_name << ", but parameter contains multiple values.");
231 0 : return sample_vec[0][0];
232 : }
233 :
234 0 : const RBParameter & RBParameters::get_extra_vector_value(const std::string & param_name) const
235 : {
236 : // Same as get_value(param_name) but for the map of extra parameters
237 0 : const auto & sample_vec = libmesh_map_find(_extra_parameters, param_name);
238 0 : libmesh_error_msg_if(sample_vec.size() == 0, "Error getting value for extra parameter " << param_name);
239 0 : return sample_vec[0];
240 : }
241 :
242 0 : Real RBParameters::get_extra_value(const std::string & param_name, const Real & default_val) const
243 : {
244 : // same as get_value(param_name, default_val) but for the map of extra parameters
245 0 : auto it = _extra_parameters.find(param_name);
246 0 : if (it == _extra_parameters.end())
247 0 : return default_val;
248 :
249 0 : libmesh_error_msg_if(it->second.size() != 1,
250 : "Requesting value for extra parameter " << param_name << ", but parameter contains multiple samples.");
251 0 : libmesh_error_msg_if(it->second[0].size() != 1,
252 : "Requesting Real value for extra parameter " << param_name << ", but parameter contains multiple values.");
253 0 : return it->second[0][0];
254 : }
255 :
256 213 : Real RBParameters::get_extra_sample_value(const std::string & param_name, std::size_t sample_idx) const
257 : {
258 213 : const auto & sample_vec = libmesh_map_find(_extra_parameters, param_name);
259 219 : libmesh_error_msg_if(sample_idx >= sample_vec.size(), "Error getting value for extra parameter " << param_name);
260 219 : libmesh_error_msg_if(sample_vec[sample_idx].size() != 1,
261 : "Requesting Real value for extra parameter " << param_name << ", but parameter contains multiple values.");
262 213 : return sample_vec[sample_idx][0];
263 : }
264 :
265 0 : const RBParameter & RBParameters::get_extra_sample_vector_value(const std::string & param_name, std::size_t sample_idx) const
266 : {
267 0 : const auto & sample_vec = libmesh_map_find(_extra_parameters, param_name);
268 0 : libmesh_error_msg_if(sample_idx >= sample_vec.size(), "Error getting value for extra parameter " << param_name);
269 0 : return sample_vec[sample_idx];
270 : }
271 :
272 0 : Real RBParameters::get_extra_sample_value(const std::string & param_name, std::size_t sample_idx, const Real & default_val) const
273 : {
274 : // same as get_sample_value(param_name, index, default_val) but for the map of extra parameters
275 0 : auto it = _extra_parameters.find(param_name);
276 0 : if (it==_extra_parameters.end() || sample_idx >= it->second.size())
277 0 : return default_val;
278 0 : libmesh_error_msg_if(it->second[sample_idx].size() != 1,
279 : "Requesting Real value for extra parameter " << param_name << ", but parameter contains multiple values.");
280 0 : return it->second[sample_idx][0];
281 : }
282 :
283 0 : const RBParameter & RBParameters::get_extra_sample_vector_value(
284 : const std::string ¶m_name,
285 : std::size_t sample_idx,
286 : const RBParameter &default_val) const
287 : {
288 0 : auto it = _extra_parameters.find(param_name);
289 0 : if (it == _extra_parameters.end() || sample_idx >= it->second.size())
290 0 : return default_val;
291 0 : return it->second[sample_idx];
292 : }
293 :
294 0 : void RBParameters::set_extra_value(const std::string & param_name, Real value)
295 : {
296 : // This version of set_extra_value() does not take an index and is provided
297 : // for backwards compatibility. It creates a vector entry for the specified
298 : // param_name, overwriting any value(s) that were present.
299 0 : _extra_parameters[param_name] = {{value}};
300 0 : }
301 :
302 0 : void RBParameters::set_extra_value(const std::string & param_name, const RBParameter & value)
303 : {
304 : // This version of set_extra_value() does not take an index and is provided
305 : // for backwards compatibility. It creates a vector entry for the specified
306 : // param_name, overwriting any value(s) that were present.
307 0 : _extra_parameters[param_name] = {value};
308 0 : }
309 :
310 1813517 : unsigned int RBParameters::n_parameters() const
311 : {
312 1813517 : return cast_int<unsigned int>(_parameters.size());
313 : }
314 :
315 71 : void RBParameters::set_n_samples(unsigned int n_samples)
316 : {
317 71 : _n_samples = n_samples;
318 71 : }
319 :
320 62822219 : unsigned int RBParameters::n_samples() const
321 : {
322 : // Quick return if there are no parameters
323 62822219 : if (_parameters.empty())
324 142 : return _n_samples;
325 :
326 : // If _parameters is not empty, we can check the number of samples in the first param
327 10658796 : auto size_first = _parameters.begin()->second.size();
328 :
329 : #ifdef DEBUG
330 : // In debug mode, verify that all parameters have the same number of samples
331 29536134 : for (const auto & pr : _parameters)
332 24206736 : libmesh_assert_msg(pr.second.size() == size_first, "All parameters must have the same number of samples.");
333 : #endif
334 :
335 : // If we made it here in DEBUG mode, then all parameters were
336 : // verified to have the same number of samples.
337 62822077 : return size_first;
338 : }
339 :
340 0 : std::set<std::string> RBParameters::get_parameter_names() const
341 : {
342 0 : std::set<std::string> param_names;
343 0 : for (const auto & pr : _parameters)
344 0 : param_names.insert(pr.first);
345 0 : return param_names;
346 : }
347 :
348 0 : std::set<std::string> RBParameters::get_extra_parameter_names() const
349 : {
350 0 : std::set<std::string> param_names;
351 0 : for (const auto & pr : _extra_parameters)
352 0 : param_names.insert(pr.first);
353 0 : return param_names;
354 : }
355 :
356 0 : void RBParameters::erase_parameter(const std::string & param_name)
357 : {
358 0 : _parameters.erase(param_name);
359 0 : }
360 :
361 0 : void RBParameters::erase_extra_parameter(const std::string & param_name)
362 : {
363 0 : _extra_parameters.erase(param_name);
364 0 : }
365 :
366 862811 : std::map<std::string,std::vector<RBParameter>>::const_iterator RBParameters::begin() const
367 : {
368 862811 : return _parameters.cbegin();
369 : }
370 :
371 862811 : std::map<std::string,std::vector<RBParameter>>::const_iterator RBParameters::end() const
372 : {
373 862811 : return _parameters.cend();
374 : }
375 :
376 408234 : std::map<std::string,std::vector<RBParameter>>::const_iterator RBParameters::extra_begin() const
377 : {
378 408234 : return _extra_parameters.cbegin();
379 : }
380 :
381 408234 : std::map<std::string,std::vector<RBParameter>>::const_iterator RBParameters::extra_end() const
382 : {
383 408234 : return _extra_parameters.cend();
384 : }
385 :
386 2136 : RBParameters::const_iterator RBParameters::begin_serialized() const
387 : {
388 2136 : return {_parameters.cbegin(), 0, 0};
389 : }
390 :
391 5056 : RBParameters::const_iterator RBParameters::end_serialized() const
392 : {
393 : // Note: the index 0 is irrelevant here since _parameters.end() does
394 : // not refer to a valid vector entry in the map.
395 5056 : return {_parameters.cend(), 0, 0};
396 : }
397 :
398 0 : RBParameters::const_iterator RBParameters::begin_serialized_extra() const
399 : {
400 0 : return {_extra_parameters.cbegin(), 0, 0};
401 : }
402 :
403 0 : RBParameters::const_iterator RBParameters::end_serialized_extra() const
404 : {
405 : // Note: the index 0 is irrelevant here since _parameters.end() does
406 : // not refer to a valid vector entry in the map.
407 0 : return {_extra_parameters.cend(), 0, 0};
408 : }
409 :
410 28415 : bool RBParameters::operator==(const RBParameters & rhs) const
411 : {
412 28415 : return (this->_parameters == rhs._parameters &&
413 28415 : this->_extra_parameters == rhs._extra_parameters);
414 : }
415 :
416 0 : bool RBParameters::operator!=(const RBParameters & rhs) const
417 : {
418 0 : return !(*this == rhs);
419 : }
420 :
421 71 : RBParameters & RBParameters::operator+= (const RBParameters & rhs)
422 : {
423 71 : libmesh_error_msg_if(this->n_samples() != rhs.n_samples(),
424 : "Can only append RBParameters objects with matching numbers of samples.");
425 :
426 : // Overwrite or add each (key, vec) pair in rhs to *this.
427 142 : for (const auto & [key, vec] : rhs._parameters)
428 71 : _parameters[key] = vec;
429 142 : for (const auto & [key, vec] : rhs._extra_parameters)
430 71 : _extra_parameters[key] = vec;
431 :
432 71 : return *this;
433 : }
434 :
435 5240 : std::string RBParameters::get_string(unsigned precision, int max_values) const
436 : {
437 5536 : std::stringstream param_stringstream;
438 5240 : param_stringstream << std::setprecision(static_cast<int>(precision)) << std::scientific;
439 :
440 27087 : for (const auto & [param_name, sample_vec] : _parameters)
441 : {
442 : // Write the param name, followed by a comma-separated list of the sample/vector values.
443 21847 : param_stringstream << param_name << ": ";
444 22463 : std::string separator = "";
445 43694 : for (const auto & value_vec : sample_vec)
446 : {
447 616 : param_stringstream << separator;
448 22463 : if (value_vec.size() == 1)
449 21847 : param_stringstream << value_vec[0];
450 : else
451 : {
452 0 : param_stringstream << "[ ";
453 0 : for (const auto val_idx : index_range(value_vec))
454 : {
455 0 : if (max_values < 0 || val_idx < static_cast<unsigned>(max_values))
456 0 : param_stringstream << value_vec[val_idx] << " ";
457 : else
458 : {
459 0 : param_stringstream << "... ";
460 0 : break;
461 : }
462 : }
463 0 : param_stringstream << "]";
464 : }
465 616 : separator = ", ";
466 : }
467 616 : param_stringstream << std::endl;
468 : }
469 :
470 5388 : return param_stringstream.str();
471 4944 : }
472 :
473 5240 : void RBParameters::print(unsigned precision, int max_values) const
474 : {
475 5240 : libMesh::out << get_string(precision, max_values);
476 5240 : }
477 :
478 : }
|