libMesh
rb_scm_evaluation.C
Go to the documentation of this file.
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 // Configuration data
21 #include "libmesh/libmesh_config.h"
22 
23 // RBSCMEvaluation should only be available
24 // if SLEPc and GLPK support is enabled.
25 #if defined(LIBMESH_HAVE_SLEPC) && (LIBMESH_HAVE_GLPK)
26 
27 // rbOOmit includes
28 #include "libmesh/rb_scm_evaluation.h"
29 #include "libmesh/rb_theta_expansion.h"
30 
31 // libMesh includes
32 #include "libmesh/dof_map.h"
33 #include "libmesh/equation_systems.h"
34 #include "libmesh/getpot.h"
35 #include "libmesh/int_range.h"
36 #include "libmesh/libmesh_logging.h"
37 #include "libmesh/numeric_vector.h"
38 #include "libmesh/sparse_matrix.h"
39 #include "libmesh/xdr_cxx.h"
40 
41 // For creating a directory
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <errno.h>
45 
46 // glpk includes
47 #include <glpk.h>
48 
49 namespace libMesh
50 {
51 
53  ParallelObject(comm_in)
54 {
55  // Clear SCM data vectors
56  B_min.clear();
57  B_max.clear();
58  C_J.clear();
59  C_J_stability_vector.clear();
60  SCM_UB_vectors.clear();
61 }
62 
64 
66 {
67  rb_theta_expansion = &rb_theta_expansion_in;
68 }
69 
71 {
72  libmesh_error_msg_if(!rb_theta_expansion, "Error: rb_theta_expansion hasn't been initialized yet");
73 
74  return *rb_theta_expansion;
75 }
76 
77 void RBSCMEvaluation::set_C_J_stability_constraint(unsigned int j, Real stability_const_in)
78 {
79  libmesh_error_msg_if(j >= C_J_stability_vector.size(), "Error: Input parameter j is too large in set_C_J_stability_constraint.");
80 
81  // we assume that C_J_stability_vector is resized elsewhere
82  // to be the same size as C_J.
83  libmesh_assert_equal_to (C_J_stability_vector.size(), C_J.size());
84 
85  C_J_stability_vector[j] = stability_const_in;
86 }
87 
89 {
90  libmesh_error_msg_if(j >= C_J_stability_vector.size(), "Error: Input parameter j is too large in get_C_J_stability_constraint.");
91 
92  return C_J_stability_vector[j];
93 }
94 
95 void RBSCMEvaluation::set_SCM_UB_vector(unsigned int j, unsigned int q, Real y_q)
96 {
97  // First make sure that j <= J
98  libmesh_error_msg_if(j >= SCM_UB_vectors.size(), "Error: We must have j < J in set_SCM_UB_vector.");
99 
100  // Next make sure that q <= Q_a or Q_a_hat
101  libmesh_error_msg_if(q >= SCM_UB_vectors[0].size(), "Error: q is too large in set_SCM_UB_vector.");
102 
103  SCM_UB_vectors[j][q] = y_q;
104 }
105 
106 Real RBSCMEvaluation::get_SCM_UB_vector(unsigned int j, unsigned int q)
107 {
108  // First make sure that j <= J
109  libmesh_error_msg_if(j >= SCM_UB_vectors.size(), "Error: We must have j < J in get_SCM_UB_vector.");
110  libmesh_error_msg_if(q >= SCM_UB_vectors[0].size(), "Error: q is too large in get_SCM_UB_vector.");
111 
112  return SCM_UB_vectors[j][q];
113 }
114 
116 {
117  libmesh_error_msg_if(j >= C_J.size(), "Error: Input parameter j is too large in get_C_J.");
118 
119  return C_J[j];
120 }
121 
122 Real RBSCMEvaluation::get_B_min(unsigned int q) const
123 {
124  libmesh_error_msg_if(q >= B_min.size(), "Error: q is too large in get_B_min.");
125 
126  return B_min[q];
127 }
128 
129 
130 Real RBSCMEvaluation::get_B_max(unsigned int q) const
131 {
132  libmesh_error_msg_if(q >= B_max.size(), "Error: q is too large in get_B_max.");
133 
134  return B_max[q];
135 }
136 
137 void RBSCMEvaluation::set_B_min(unsigned int q, Real B_min_val)
138 {
139  libmesh_error_msg_if(q >= B_min.size(), "Error: q is too large in set_B_min.");
140 
141  B_min[q] = B_min_val;
142 }
143 
144 void RBSCMEvaluation::set_B_max(unsigned int q, Real B_max_val)
145 {
146  libmesh_error_msg_if(q >= B_max.size(), "Error: q is too large in set_B_max.");
147 
148  B_max[q] = B_max_val;
149 }
150 
152 {
153  LOG_SCOPE("get_SCM_LB()", "RBSCMEvaluation");
154 
155  // Initialize the LP
156  glp_prob * lp;
157  lp = glp_create_prob();
158  glp_set_obj_dir(lp,GLP_MIN);
159 
160  // Add columns to the LP: corresponds to
161  // the variables y_1,...y_Q_a.
162  // These are the same for each \mu in the SCM
163  // training set, hence can do this up front.
164  glp_add_cols(lp,rb_theta_expansion->get_n_A_terms());
165 
166  for (unsigned int q=0; q<rb_theta_expansion->get_n_A_terms(); q++)
167  {
168  if (B_max[q] < B_min[q]) // Invalid bound, set as free variable
169  {
170  // GLPK indexing is not zero based!
171  glp_set_col_bnds(lp, q+1, GLP_FR, 0., 0.);
172  }
173  else
174  {
175  // GLPK indexing is not zero based!
176  glp_set_col_bnds(lp, q+1, GLP_DB, double(B_min[q]), double(B_max[q]));
177  }
178 
179  // If B_max is not defined, just set lower bounds...
180  // glp_set_col_bnds(lp, q+1, GLP_LO, B_min[q], 0.);
181  }
182 
183 
184  // Add rows to the LP: corresponds to the auxiliary
185  // variables that define the constraints at each
186  // mu \in C_J_M
187  unsigned int n_rows = cast_int<unsigned int>(C_J.size());
188  glp_add_rows(lp, n_rows);
189 
190  // Now put current_parameters in saved_parameters
192 
193  unsigned int matrix_size = n_rows*rb_theta_expansion->get_n_A_terms();
194  std::vector<int> ia(matrix_size+1);
195  std::vector<int> ja(matrix_size+1);
196  std::vector<double> ar(matrix_size+1);
197  unsigned int count=0;
198  for (unsigned int m=0; m<n_rows; m++)
199  {
201 
202  // Set the lower bound on the auxiliary variable
203  // due to the stability constant at mu_index
204  glp_set_row_bnds(lp, m+1, GLP_LO, double(C_J_stability_vector[m]), 0.);
205 
206  // Now define the matrix that relates the y's
207  // to the auxiliary variables at the current
208  // value of mu.
209  for (unsigned int q=0; q<rb_theta_expansion->get_n_A_terms(); q++)
210  {
211  count++;
212 
213  ia[count] = m+1;
214  ja[count] = q+1;
215 
216  // This can only handle Reals right now
217  ar[count] = double(libmesh_real( rb_theta_expansion->eval_A_theta(q,get_parameters()) ));
218  }
219  }
220 
221  // Now load the original parameters back into current_parameters
222  // in order to set the coefficients of the objective function
224 
225  glp_load_matrix(lp, matrix_size, ia.data(), ja.data(), ar.data());
226 
227  for (unsigned int q=0; q<rb_theta_expansion->get_n_A_terms(); q++)
228  {
229  glp_set_obj_coef(lp,q+1, double(libmesh_real( rb_theta_expansion->eval_A_theta(q,get_parameters()) )) );
230  }
231 
232  // Use this command to initialize the basis for the LP
233  // since default behavior is to use the basis from
234  // the previous solve, but that might become singular
235  // if we switch the order of constraints (as can
236  // happen when we generate a new C_J_M)
237  //lpx_cpx_basis(lp); //glp_cpx_basis(lp);
238 
239  glp_smcp parm;
240  glp_init_smcp(&parm);
241  parm.msg_lev = GLP_MSG_ERR;
242  parm.meth = GLP_DUAL;
243 
244 
245  // use the simplex method and solve the LP
246  glp_simplex(lp, &parm);
247 
248  Real min_J_obj = glp_get_obj_val(lp);
249 
250  // int simplex_status = glp_get_status(lp);
251  // if (simplex_status == GLP_UNBND)
252  // {
253  // libMesh::out << "Simplex method gave unbounded solution." << std::endl;
254  // min_J_obj = std::numeric_limits<Real>::quiet_NaN();
255  // }
256  // else
257  // {
258  // min_J_obj = glp_get_obj_val(lp);
259  // }
260 
261  // Destroy the LP
262  glp_delete_prob(lp);
263 
264  return min_J_obj;
265 }
266 
268 {
269  LOG_SCOPE("get_SCM_UB()", "RBSCMEvaluation");
270 
271  // Add rows to the LP: corresponds to the auxiliary
272  // variables that define the constraints at each
273  // mu \in C_J
274  unsigned int n_rows = cast_int<unsigned int>(C_J.size());
275 
276  // For each mu, we just find the minimum of J_obj over
277  // the subset of vectors in SCM_UB_vectors corresponding
278  // to C_J_M (SCM_UB_vectors contains vectors for all of
279  // C_J).
280  Real min_J_obj = 0.;
281  for (unsigned int m=0; m<n_rows; m++)
282  {
283  const std::vector<Real> UB_vector = SCM_UB_vectors[m];
284 
285  Real J_obj = 0.;
286  for (unsigned int q=0; q<rb_theta_expansion->get_n_A_terms(); q++)
287  {
288  J_obj += libmesh_real( rb_theta_expansion->eval_A_theta(q,get_parameters()) )*UB_vector[q];
289  }
290 
291  if ((m==0) || (J_obj < min_J_obj))
292  {
293  min_J_obj = J_obj;
294  }
295  }
296 
297  return min_J_obj;
298 }
299 
301 {
302  set_parameters(C_J[C_J_index]);
303 }
304 
306 {
308 }
309 
311 {
313 }
314 
315 void RBSCMEvaluation::legacy_write_offline_data_to_files(const std::string & directory_name,
316  const bool write_binary_data)
317 {
318  LOG_SCOPE("legacy_write_offline_data_to_files()", "RBSCMEvaluation");
319 
320  if (this->processor_id() == 0)
321  {
322  // Make a directory to store all the data files
323  if (mkdir(directory_name.c_str(), 0777) == -1)
324  {
325  libMesh::out << "In RBSCMEvaluation::write_offline_data_to_files, directory "
326  << directory_name << " already exists, overwriting contents." << std::endl;
327  }
328 
329  // The writing mode: ENCODE for binary, WRITE for ASCII
330  XdrMODE mode = write_binary_data ? ENCODE : WRITE;
331 
332  // The suffix to use for all the files that are written out
333  const std::string suffix = write_binary_data ? ".xdr" : ".dat";
334 
335  // Stream for building the file names
336  std::ostringstream file_name;
337 
338  // Write out the parameter ranges
339  file_name.str("");
340  file_name << directory_name << "/parameter_ranges" << suffix;
341  std::string continuous_param_file_name = file_name.str();
342 
343  // Write out the discrete parameter values
344  file_name.str("");
345  file_name << directory_name << "/discrete_parameter_values" << suffix;
346  std::string discrete_param_file_name = file_name.str();
347 
348  write_parameter_data_to_files(continuous_param_file_name,
349  discrete_param_file_name,
350  write_binary_data);
351 
352  // Write out the bounding box min values
353  file_name.str("");
354  file_name << directory_name << "/B_min" << suffix;
355  Xdr B_min_out(file_name.str(), mode);
356 
357  for (auto i : make_range(B_min.size()))
358  {
359  Real B_min_i = get_B_min(i);
360  B_min_out << B_min_i;
361  }
362  B_min_out.close();
363 
364 
365  // Write out the bounding box max values
366  file_name.str("");
367  file_name << directory_name << "/B_max" << suffix;
368  Xdr B_max_out(file_name.str(), mode);
369 
370  for (auto i : make_range(B_max.size()))
371  {
372  Real B_max_i = get_B_max(i);
373  B_max_out << B_max_i;
374  }
375  B_max_out.close();
376 
377  // Write out the length of the C_J data
378  file_name.str("");
379  file_name << directory_name << "/C_J_length" << suffix;
380  Xdr C_J_length_out(file_name.str(), mode);
381 
382  unsigned int C_J_length = cast_int<unsigned int>(C_J.size());
383  C_J_length_out << C_J_length;
384  C_J_length_out.close();
385 
386  // Write out C_J_stability_vector
387  file_name.str("");
388  file_name << directory_name << "/C_J_stability_vector" << suffix;
389  Xdr C_J_stability_vector_out(file_name.str(), mode);
390 
391  for (auto i : make_range(C_J_stability_vector.size()))
392  {
393  Real C_J_stability_constraint_i = get_C_J_stability_constraint(i);
394  C_J_stability_vector_out << C_J_stability_constraint_i;
395  }
396  C_J_stability_vector_out.close();
397 
398  // Write out C_J
399  file_name.str("");
400  file_name << directory_name << "/C_J" << suffix;
401  Xdr C_J_out(file_name.str(), mode);
402 
403  for (const auto & param : C_J)
404  for (const auto & pr : param)
405  for (const auto & value_vector : pr.second)
406  {
407  // Need to make a copy of the value so that it's not const
408  // Xdr is not templated on const's
409  libmesh_error_msg_if(value_vector.size() != 1,
410  "Error: multi-value RB parameters are not yet supported here.");
411  Real param_value = value_vector[0];
412  C_J_out << param_value;
413  }
414  C_J_out.close();
415 
416  // Write out SCM_UB_vectors get_SCM_UB_vector
417  file_name.str("");
418  file_name << directory_name << "/SCM_UB_vectors" << suffix;
419  Xdr SCM_UB_vectors_out(file_name.str(), mode);
420 
421  for (auto i : make_range(SCM_UB_vectors.size()))
422  for (auto j : make_range(rb_theta_expansion->get_n_A_terms()))
423  {
424  Real SCM_UB_vector_ij = get_SCM_UB_vector(i,j);
425  SCM_UB_vectors_out << SCM_UB_vector_ij;
426  }
427  SCM_UB_vectors_out.close();
428  }
429 }
430 
431 
432 void RBSCMEvaluation::legacy_read_offline_data_from_files(const std::string & directory_name,
433  const bool read_binary_data)
434 {
435  LOG_SCOPE("legacy_read_offline_data_from_files()", "RBSCMEvaluation");
436 
437  // The reading mode: DECODE for binary, READ for ASCII
438  XdrMODE mode = read_binary_data ? DECODE : READ;
439 
440  // The suffix to use for all the files that are written out
441  const std::string suffix = read_binary_data ? ".xdr" : ".dat";
442 
443  // The string stream we'll use to make the file names
444  std::ostringstream file_name;
445 
446  // Read in the parameter ranges
447  file_name.str("");
448  file_name << directory_name << "/parameter_ranges" << suffix;
449  std::string continuous_param_file_name = file_name.str();
450 
451  // Read in the discrete parameter values
452  file_name.str("");
453  file_name << directory_name << "/discrete_parameter_values" << suffix;
454  std::string discrete_param_file_name = file_name.str();
455  read_parameter_data_from_files(continuous_param_file_name,
456  discrete_param_file_name,
457  read_binary_data);
458 
459  // Read in the bounding box min values
460  // Note that there are Q_a values
461  file_name.str("");
462  file_name << directory_name << "/B_min" << suffix;
463  Xdr B_min_in(file_name.str(), mode);
464 
465  B_min.clear();
466  for (unsigned int i=0; i<rb_theta_expansion->get_n_A_terms(); i++)
467  {
468  Real B_min_val;
469  B_min_in >> B_min_val;
470  B_min.push_back(B_min_val);
471  }
472  B_min_in.close();
473 
474 
475  // Read in the bounding box max values
476  // Note that there are Q_a values
477  file_name.str("");
478  file_name << directory_name << "/B_max" << suffix;
479  Xdr B_max_in(file_name.str(), mode);
480 
481  B_max.clear();
482  for (unsigned int i=0; i<rb_theta_expansion->get_n_A_terms(); i++)
483  {
484  Real B_max_val;
485  B_max_in >> B_max_val;
486  B_max.push_back(B_max_val);
487  }
488 
489  // Read in the length of the C_J data
490  file_name.str("");
491  file_name << directory_name << "/C_J_length" << suffix;
492  Xdr C_J_length_in(file_name.str(), mode);
493 
494  unsigned int C_J_length;
495  C_J_length_in >> C_J_length;
496  C_J_length_in.close();
497 
498  // Read in C_J_stability_vector
499  file_name.str("");
500  file_name << directory_name << "/C_J_stability_vector" << suffix;
501  Xdr C_J_stability_vector_in(file_name.str(), mode);
502 
503  C_J_stability_vector.clear();
504  for (unsigned int i=0; i<C_J_length; i++)
505  {
506  Real C_J_stability_val;
507  C_J_stability_vector_in >> C_J_stability_val;
508  C_J_stability_vector.push_back(C_J_stability_val);
509  }
510  C_J_stability_vector_in.close();
511 
512  // Read in C_J
513  file_name.str("");
514  file_name << directory_name << "/C_J" << suffix;
515  Xdr C_J_in(file_name.str(), mode);
516 
517  // Resize C_J based on C_J_stability_vector and Q_a
518  C_J.resize( C_J_length );
519  for (auto & params : C_J)
520  for (const auto & pr : get_parameters())
521  {
522  const std::string & param_name = pr.first;
523  Real param_value;
524  C_J_in >> param_value;
525  params.set_value(param_name, param_value);
526  }
527  C_J_in.close();
528 
529 
530  // Read in SCM_UB_vectors get_SCM_UB_vector
531  file_name.str("");
532  file_name << directory_name << "/SCM_UB_vectors" << suffix;
533  Xdr SCM_UB_vectors_in(file_name.str(), mode);
534 
535  // Resize SCM_UB_vectors based on C_J_stability_vector and Q_a
536  SCM_UB_vectors.resize( C_J_stability_vector.size() );
537  for (auto i : index_range(SCM_UB_vectors))
538  {
540  for (unsigned int j=0; j<rb_theta_expansion->get_n_A_terms(); j++)
541  {
542  SCM_UB_vectors_in >> SCM_UB_vectors[i][j];
543  }
544  }
545  SCM_UB_vectors_in.close();
546 }
547 
548 } // namespace libMesh
549 
550 #endif // LIBMESH_HAVE_SLEPC && LIBMESH_HAVE_GLPK
T libmesh_real(T a)
std::vector< Real > B_min
B_min, B_max define the bounding box.
virtual Real get_SCM_UB()
Evaluate single SCM upper bound.
virtual Number eval_A_theta(unsigned int q, const RBParameters &mu) const
Evaluate theta_q_a at the current parameter.
void set_rb_theta_expansion(RBThetaExpansion &rb_theta_expansion_in)
Set the RBThetaExpansion object.
void set_SCM_UB_vector(unsigned int j, unsigned int q, Real y_q)
Set entries of SCM_UB_vector, which stores the vector y, corresponding to the minimizing eigenvectors...
void write_parameter_data_to_files(const std::string &continuous_param_file_name, const std::string &discrete_param_file_name, const bool write_binary_data)
Write out the parameter ranges to files.
Real get_B_min(unsigned int i) const
Get B_min and B_max.
void close()
Closes the file if it is open.
Definition: xdr_cxx.C:277
unsigned int get_n_A_terms() const
Get Q_a, the number of terms in the affine expansion for the bilinear form.
int mkdir(const char *pathname)
Create a directory.
Definition: utility.C:152
virtual void save_current_parameters()
Helper function to save current_parameters in saved_parameters.
void read_parameter_data_from_files(const std::string &continuous_param_file_name, const std::string &discrete_param_file_name, const bool read_binary_data)
Read in the parameter ranges from files.
The libMesh namespace provides an interface to certain functionality in the library.
RBThetaExpansion & get_rb_theta_expansion()
Get a reference to the rb_theta_expansion.
std::vector< Real > B_max
virtual void legacy_read_offline_data_from_files(const std::string &directory_name="offline_data", const bool read_binary_data=true)
Read in the saved Offline reduced basis data to initialize the system for Online solves.
This class stores the set of RBTheta functor objects that define the "parameter-dependent expansion" ...
std::vector< std::vector< Real > > SCM_UB_vectors
This matrix stores the infimizing vectors y_1( ),...,y_Q_a( ), for each in C_J, which are used in co...
std::vector< Real > C_J_stability_vector
Vector storing the (truth) stability values at the parameters in C_J.
virtual Real get_SCM_LB()
Evaluate single SCM lower bound.
XdrMODE
Defines an enum for read/write mode in Xdr format.
Definition: enum_xdr_mode.h:35
const RBParameters & get_C_J_entry(unsigned int j)
Get entry of C_J.
virtual void reload_current_parameters()
Helper function to (re)load current_parameters from saved_parameters.
std::vector< RBParameters > C_J
Vector storing the greedily selected parameters during SCM training.
RBThetaExpansion * rb_theta_expansion
A pointer to to the object that stores the theta expansion.
void set_B_min(unsigned int i, Real B_min_val)
Set B_min and B_max.
void set_C_J_stability_constraint(unsigned int j, Real stability_constraint_in)
Set stability constraints (i.e.
RBSCMEvaluation(const Parallel::Communicator &comm)
Constructor.
virtual void legacy_write_offline_data_to_files(const std::string &directory_name="offline_data", const bool write_binary_data=true)
Write out all the data to text files in order to segregate the Offline stage from the Online stage...
const RBParameters & get_parameters() const
Get the current parameters.
This class is part of the rbOOmit framework.
Definition: rb_parameters.h:52
An object whose state is distributed along a set of processors.
This class implements a C++ interface to the XDR (eXternal Data Representation) format.
Definition: xdr_cxx.h:67
virtual void set_current_parameters_from_C_J(unsigned int C_J_index)
Set parameters based on values saved in "C_J".
bool set_parameters(const RBParameters &params)
Set the current parameters to params The parameters are checked for validity; an error is thrown if t...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void set_B_max(unsigned int i, Real B_max_val)
Real get_C_J_stability_constraint(unsigned int j) const
Get stability constraints (i.e.
OStreamProxy out
Real get_B_max(unsigned int i) const
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:140
virtual ~RBSCMEvaluation()
Destructor.
processor_id_type processor_id() const
RBParameters saved_parameters
Vector in which to save a parameter set.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:117
Real get_SCM_UB_vector(unsigned int j, unsigned int q)
Get entries of SCM_UB_vector, which stores the vector y, corresponding to the minimizing eigenvectors...