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/xdr_cxx.h"
22 
23 // rbOOmit includes
24 #include "libmesh/rb_parametrized.h"
25 
26 // C++ includes
27 #include <sstream>
28 #include <fstream>
29 #include <algorithm> // std::min_element
30 
31 namespace libMesh
32 {
33 
34 // ------------------------------------------------------------
35 // RBParameters implementation
36 
RBParametrized()37 RBParametrized::RBParametrized()
38   :
39   verbose_mode(false),
40   parameters_initialized(false)
41 {
42   parameters.clear();
43   parameters_min.clear();
44   parameters_max.clear();
45 }
46 
~RBParametrized()47 RBParametrized::~RBParametrized()
48 {
49   this->clear();
50 }
51 
clear()52 void RBParametrized::clear()
53 {
54   parameters.clear();
55   parameters_min.clear();
56   parameters_max.clear();
57   parameters_initialized = false;
58 }
59 
initialize_parameters(const RBParameters & mu_min_in,const RBParameters & mu_max_in,const std::map<std::string,std::vector<Real>> & discrete_parameter_values)60 void RBParametrized::initialize_parameters(const RBParameters & mu_min_in,
61                                            const RBParameters & mu_max_in,
62                                            const std::map<std::string, std::vector<Real>> & discrete_parameter_values)
63 {
64   // Check that the min/max vectors are valid
65   libmesh_error_msg_if(mu_min_in.n_parameters() != mu_max_in.n_parameters(),
66                        "Error: Invalid mu_min/mu_max in RBParameters constructor.");
67 
68   for (const auto & pr : mu_min_in)
69     libmesh_error_msg_if(mu_min_in.get_value(pr.first) > mu_max_in.get_value(pr.first),
70                          "Error: Invalid mu_min/mu_max in RBParameters constructor.");
71 
72   parameters_min = mu_min_in;
73   parameters_max = mu_max_in;
74 
75   // Add in min/max values due to the discrete parameters
76     for (const auto & pr : discrete_parameter_values)
77       {
78         libmesh_error_msg_if(pr.second.empty(), "Error: List of discrete parameters for " << pr.first << " is empty.");
79 
80         Real min_val = *std::min_element(pr.second.begin(), pr.second.end());
81         Real max_val = *std::max_element(pr.second.begin(), pr.second.end());
82 
83         libmesh_assert_less_equal(min_val,max_val);
84 
85         parameters_min.set_value(pr.first, min_val);
86         parameters_max.set_value(pr.first, max_val);
87       }
88 
89     _discrete_parameter_values = discrete_parameter_values;
90 
91   parameters_initialized = true;
92 
93   // Initialize the current parameters to parameters_min
94   set_parameters(parameters_min);
95 }
96 
initialize_parameters(const RBParametrized & rb_parametrized)97 void RBParametrized::initialize_parameters(const RBParametrized & rb_parametrized)
98 {
99   initialize_parameters(rb_parametrized.get_parameters_min(),
100                         rb_parametrized.get_parameters_max(),
101                         rb_parametrized.get_discrete_parameter_values());
102 }
103 
get_n_params()104 unsigned int RBParametrized::get_n_params() const
105 {
106   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_n_params");
107 
108   libmesh_assert_equal_to ( parameters_min.n_parameters(), parameters_max.n_parameters() );
109 
110   return parameters_min.n_parameters();
111 }
112 
get_n_continuous_params()113 unsigned int RBParametrized::get_n_continuous_params() const
114 {
115   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_n_continuous_params");
116 
117   libmesh_assert(get_n_params() >= get_n_discrete_params());
118 
119   return static_cast<unsigned int>(get_n_params() - get_n_discrete_params());
120 }
121 
get_n_discrete_params()122 unsigned int RBParametrized::get_n_discrete_params() const
123 {
124   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_n_discrete_params");
125 
126   return cast_int<unsigned int>
127     (get_discrete_parameter_values().size());
128 }
129 
get_parameter_names()130 std::set<std::string> RBParametrized::get_parameter_names() const
131 {
132   libmesh_deprecated();
133   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_parameter_names");
134 
135   std::set<std::string> parameter_names;
136   const auto & params_map = parameters_min.get_parameters_map();
137   for (const auto & pr : params_map)
138     parameter_names.insert(pr.first);
139 
140   return parameter_names;
141 }
142 
set_parameters(const RBParameters & params)143 void RBParametrized::set_parameters(const RBParameters & params)
144 {
145   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::set_current_parameters");
146 
147   valid_params(params); // Terminates if params has the wrong number of parameters
148 
149   // Make a copy of params (default assignment operator just does memberwise copy, which is sufficient here)
150   this->parameters = params;
151 }
152 
get_parameters()153 const RBParameters & RBParametrized::get_parameters() const
154 {
155   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_current_parameters");
156 
157   return parameters;
158 }
159 
get_parameters_min()160 const RBParameters & RBParametrized::get_parameters_min() const
161 {
162   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_parameters_min");
163 
164   return parameters_min;
165 }
166 
get_parameters_max()167 const RBParameters & RBParametrized::get_parameters_max() const
168 {
169   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_parameters_max");
170 
171   return parameters_max;
172 }
173 
get_parameter_min(const std::string & param_name)174 Real RBParametrized::get_parameter_min(const std::string & param_name) const
175 {
176   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_parameter_min");
177 
178   return parameters_min.get_value(param_name);
179 }
180 
get_parameter_max(const std::string & param_name)181 Real RBParametrized::get_parameter_max(const std::string & param_name) const
182 {
183   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_parameter_max");
184 
185   return parameters_max.get_value(param_name);
186 }
187 
print_parameters()188 void RBParametrized::print_parameters() const
189 {
190   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::print_current_parameters");
191 
192   get_parameters().print();
193 }
194 
write_parameter_data_to_files(const std::string & continuous_param_file_name,const std::string & discrete_param_file_name,const bool write_binary_data)195 void RBParametrized::write_parameter_data_to_files(const std::string & continuous_param_file_name,
196                                                    const std::string & discrete_param_file_name,
197                                                    const bool write_binary_data)
198 {
199   write_parameter_ranges_to_file(continuous_param_file_name, write_binary_data);
200   write_discrete_parameter_values_to_file(discrete_param_file_name, write_binary_data);
201 }
202 
write_parameter_ranges_to_file(const std::string & file_name,const bool write_binary_data)203 void RBParametrized::write_parameter_ranges_to_file(const std::string & file_name,
204                                                     const bool write_binary_data)
205 {
206   // The writing mode: ENCODE for binary, WRITE for ASCII
207   XdrMODE mode = write_binary_data ? ENCODE : WRITE;
208 
209   // Write out the parameter ranges
210   Xdr parameter_ranges_out(file_name, mode);
211   unsigned int n_continuous_params = get_n_continuous_params();
212   parameter_ranges_out << n_continuous_params;
213 
214   for (const auto & pr : get_parameters_min())
215     {
216       std::string param_name = pr.first;
217       if (!is_discrete_parameter(param_name))
218         {
219           Real param_value = pr.second;
220           parameter_ranges_out << param_name << param_value;
221         }
222     }
223 
224   for (const auto & pr : get_parameters_max())
225     {
226       std::string param_name = pr.first;
227       if (!is_discrete_parameter(param_name))
228         {
229           Real param_value = pr.second;
230           parameter_ranges_out << param_name << param_value;
231         }
232     }
233   parameter_ranges_out.close();
234 }
235 
write_discrete_parameter_values_to_file(const std::string & file_name,const bool write_binary_data)236 void RBParametrized::write_discrete_parameter_values_to_file(const std::string & file_name,
237                                                              const bool write_binary_data)
238 {
239   // write out the discrete parameters, if we have any
240   if (get_n_discrete_params() > 0)
241     {
242       // The writing mode: ENCODE for binary, WRITE for ASCII
243       XdrMODE mode = write_binary_data ? ENCODE : WRITE;
244 
245       Xdr discrete_parameters_out(file_name, mode);
246       unsigned int n_discrete_params = get_n_discrete_params();
247       discrete_parameters_out << n_discrete_params;
248 
249       for (const auto & pr : get_discrete_parameter_values())
250         {
251           std::string param_name = pr.first;
252           unsigned int n_discrete_values = cast_int<unsigned int>
253             (pr.second.size());
254           discrete_parameters_out << param_name << n_discrete_values;
255 
256           for (unsigned int i=0; i<n_discrete_values; i++)
257             {
258               Real discrete_value = pr.second[i];
259               discrete_parameters_out << discrete_value;
260             }
261         }
262     }
263 }
264 
read_parameter_data_from_files(const std::string & continuous_param_file_name,const std::string & discrete_param_file_name,const bool read_binary_data)265 void RBParametrized::read_parameter_data_from_files(const std::string & continuous_param_file_name,
266                                                     const std::string & discrete_param_file_name,
267                                                     const bool read_binary_data)
268 {
269   RBParameters param_min;
270   RBParameters param_max;
271   read_parameter_ranges_from_file(continuous_param_file_name,
272                                   read_binary_data,
273                                   param_min,
274                                   param_max);
275 
276   std::map<std::string, std::vector<Real>> discrete_parameter_values_in;
277   read_discrete_parameter_values_from_file(discrete_param_file_name,
278                                            read_binary_data,
279                                            discrete_parameter_values_in);
280 
281   initialize_parameters(param_min, param_max, discrete_parameter_values_in);
282 }
283 
read_parameter_ranges_from_file(const std::string & file_name,const bool read_binary_data,RBParameters & param_min,RBParameters & param_max)284 void RBParametrized::read_parameter_ranges_from_file(const std::string & file_name,
285                                                      const bool read_binary_data,
286                                                      RBParameters & param_min,
287                                                      RBParameters & param_max)
288 {
289   // The reading mode: DECODE for binary, READ for ASCII
290   XdrMODE mode = read_binary_data ? DECODE : READ;
291 
292   // Read in the parameter ranges
293   Xdr parameter_ranges_in(file_name, mode);
294   unsigned int n_continuous_params;
295   parameter_ranges_in >> n_continuous_params;
296 
297   for (unsigned int i=0; i<n_continuous_params; i++)
298     {
299       std::string param_name;
300       Real param_value;
301 
302       parameter_ranges_in >> param_name;
303       parameter_ranges_in >> param_value;
304 
305       param_min.set_value(param_name, param_value);
306     }
307   for (unsigned int i=0; i<n_continuous_params; i++)
308     {
309       std::string param_name;
310       Real param_value;
311 
312       parameter_ranges_in >> param_name;
313       parameter_ranges_in >> param_value;
314 
315       param_max.set_value(param_name, param_value);
316     }
317 
318   parameter_ranges_in.close();
319 }
320 
read_discrete_parameter_values_from_file(const std::string & file_name,const bool read_binary_data,std::map<std::string,std::vector<Real>> & discrete_parameter_values)321 void RBParametrized::read_discrete_parameter_values_from_file(const std::string & file_name,
322                                                               const bool read_binary_data,
323                                                               std::map<std::string, std::vector<Real>> & discrete_parameter_values)
324 {
325   // read in the discrete parameters, if we have any
326   std::ifstream check_if_file_exists(file_name.c_str());
327   if (check_if_file_exists.good())
328     {
329       // The reading mode: DECODE for binary, READ for ASCII
330       XdrMODE mode = read_binary_data ? DECODE : READ;
331 
332       // Read in the parameter ranges
333       Xdr discrete_parameter_values_in(file_name, mode);
334       unsigned int n_discrete_params;
335       discrete_parameter_values_in >> n_discrete_params;
336 
337       for (unsigned int i=0; i<n_discrete_params; i++)
338         {
339           std::string param_name;
340           discrete_parameter_values_in >> param_name;
341 
342           unsigned int n_discrete_values;
343           discrete_parameter_values_in >> n_discrete_values;
344 
345           std::vector<Real> discrete_values(n_discrete_values);
346           for (auto & val : discrete_values)
347             discrete_parameter_values_in >> val;
348 
349           discrete_parameter_values[param_name] = discrete_values;
350         }
351     }
352 }
353 
is_discrete_parameter(const std::string & mu_name)354 bool RBParametrized::is_discrete_parameter(const std::string & mu_name) const
355 {
356   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::is_discrete_parameter");
357 
358   return (_discrete_parameter_values.find(mu_name) != _discrete_parameter_values.end());
359 }
360 
get_discrete_parameter_values()361 const std::map<std::string, std::vector<Real>> & RBParametrized::get_discrete_parameter_values() const
362 {
363   libmesh_error_msg_if(!parameters_initialized, "Error: parameters not initialized in RBParametrized::get_discrete_parameter_values");
364 
365   return _discrete_parameter_values;
366 }
367 
print_discrete_parameter_values()368 void RBParametrized::print_discrete_parameter_values() const
369 {
370   for (const auto & pr : get_discrete_parameter_values())
371     {
372       libMesh::out << "Discrete parameter " << pr.first << ", values: ";
373 
374       const std::vector<Real> & values = pr.second;
375       for (const auto & value : values)
376         libMesh::out << value << " ";
377       libMesh::out << std::endl;
378     }
379 }
380 
valid_params(const RBParameters & params)381 bool RBParametrized::valid_params(const RBParameters & params)
382 {
383   libmesh_error_msg_if(params.n_parameters() != get_n_params(), "Error: Number of parameters don't match");
384 
385   bool valid = true;
386   for (const auto & pr : params)
387     {
388       const std::string & param_name = pr.first;
389       valid = valid && ( (get_parameter_min(param_name) <= params.get_value(param_name)) &&
390                          (params.get_value(param_name) <= get_parameter_max(param_name)) );
391 
392       if (is_discrete_parameter(param_name))
393         {
394           // make sure params.get_value(param_name) is sufficiently close
395           // to one of the discrete parameter values
396           valid = valid && is_value_in_list(params.get_value(param_name),
397                                             get_discrete_parameter_values().find(param_name)->second,
398                                             TOLERANCE);
399         }
400     }
401 
402   if (!valid && verbose_mode)
403     libMesh::out << "Warning: parameter is outside parameter range" << std::endl;
404 
405   return valid;
406 }
407 
get_closest_value(Real value,const std::vector<Real> & list_of_values)408 Real RBParametrized::get_closest_value(Real value, const std::vector<Real> & list_of_values)
409 {
410   libmesh_error_msg_if(list_of_values.empty(), "Error: list_of_values is empty.");
411 
412   Real min_distance = std::numeric_limits<Real>::max();
413   Real closest_val = 0.;
414   for (const auto & current_value : list_of_values)
415     {
416       Real distance = std::abs(value - current_value);
417       if (distance < min_distance)
418         {
419           min_distance = distance;
420           closest_val = current_value;
421         }
422     }
423 
424   return closest_val;
425 }
426 
is_value_in_list(Real value,const std::vector<Real> & list_of_values,Real tol)427 bool RBParametrized::is_value_in_list(Real value, const std::vector<Real> & list_of_values, Real tol)
428 {
429   Real closest_value = get_closest_value(value, list_of_values);
430 
431   // Check if relative tolerance is satisfied
432   Real rel_error = std::abs(value - closest_value) / std::abs(value);
433   if (rel_error <= tol)
434     {
435       return true;
436     }
437 
438   // If relative tolerance isn't satisfied, we should still check an absolute
439   // error, since relative tolerance can be misleading if value is close to zero
440   Real abs_error = std::abs(value - closest_value);
441   return (abs_error <= tol);
442 }
443 
444 } // namespace libMesh
445