libMesh
Loading...
Searching...
No Matches
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
49namespace 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();
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
77void 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
95void 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
106Real 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
122Real 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
130Real 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
137void 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
144void 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
309
314
315void 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()))
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
432void 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
An object whose state is distributed along a set of processors.
processor_id_type processor_id() const
This class is part of the rbOOmit framework.
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.
const RBParameters & get_parameters() const
Get the current parameters.
bool set_parameters(const RBParameters &params)
Set the current parameters to params The parameters are checked for validity; an error is thrown if t...
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.
virtual ~RBSCMEvaluation()
Destructor.
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.
Real get_B_min(unsigned int i) const
Get B_min and B_max.
RBSCMEvaluation(const Parallel::Communicator &comm)
Constructor.
Real get_C_J_stability_constraint(unsigned int j) const
Get stability constraints (i.e.
std::vector< Real > B_max
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...
virtual Real get_SCM_LB()
Evaluate single SCM lower bound.
RBParameters saved_parameters
Vector in which to save a parameter set.
RBThetaExpansion & get_rb_theta_expansion()
Get a reference to the rb_theta_expansion.
Real get_B_max(unsigned int i) const
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...
virtual void set_current_parameters_from_C_J(unsigned int C_J_index)
Set parameters based on values saved in "C_J".
virtual Real get_SCM_UB()
Evaluate single SCM upper bound.
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.
RBThetaExpansion * rb_theta_expansion
A pointer to to the object that stores the theta expansion.
void set_B_max(unsigned int i, Real B_max_val)
std::vector< Real > C_J_stability_vector
Vector storing the (truth) stability values at the parameters in C_J.
std::vector< Real > B_min
B_min, B_max define the bounding box.
virtual void reload_current_parameters()
Helper function to (re)load current_parameters from saved_parameters.
void set_C_J_stability_constraint(unsigned int j, Real stability_constraint_in)
Set stability constraints (i.e.
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...
void set_B_min(unsigned int i, Real B_min_val)
Set B_min and B_max.
void set_rb_theta_expansion(RBThetaExpansion &rb_theta_expansion_in)
Set the RBThetaExpansion object.
const RBParameters & get_C_J_entry(unsigned int j)
Get entry of C_J.
virtual void save_current_parameters()
Helper function to save current_parameters in saved_parameters.
std::vector< RBParameters > C_J
Vector storing the greedily selected parameters during SCM training.
This class stores the set of RBTheta functor objects that define the "parameter-dependent expansion" ...
unsigned int get_n_A_terms() const
Get Q_a, the number of terms in the affine expansion for the bilinear form.
virtual Number eval_A_theta(unsigned int q, const RBParameters &mu) const
Evaluate theta_q_a at the current parameter.
This class implements a C++ interface to the XDR (eXternal Data Representation) format.
Definition xdr_cxx.h:68
void close()
Closes the file if it is open.
Definition xdr_cxx.C:278
The libMesh namespace provides an interface to certain functionality in the library.
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:153
T libmesh_real(T a)
OStreamProxy out
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
XdrMODE
Defines an enum for read/write mode in Xdr format.
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:176