libMesh
transient_rb_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 // rbOOmit includes
21 #include "libmesh/transient_rb_evaluation.h"
22 #include "libmesh/transient_rb_theta_expansion.h"
23 
24 // libMesh includes
25 #include "libmesh/getpot.h"
26 #include "libmesh/int_range.h"
27 #include "libmesh/libmesh_logging.h"
28 #include "libmesh/numeric_vector.h"
29 #include "libmesh/xdr_cxx.h"
30 
31 // C++ includes
32 #include <fstream>
33 #include <sstream>
34 #include <iomanip>
35 
36 namespace libMesh
37 {
38 
40  RBEvaluation(comm_in),
41  _rb_solve_data_cached(false)
42 {
43  // Indicate that we need to compute the RB
44  // inner product matrix in this case
46 }
47 
49 
51 {
52  Parent::clear();
53 
55 }
56 
58 {
60 
61  // Delete the M_q representors
62  M_q_representor.clear();
63 }
64 
65 void TransientRBEvaluation::resize_data_structures(const unsigned int Nmax,
66  bool resize_error_bound_data)
67 {
68  LOG_SCOPE("resize_data_structures()", "TransientRBEvaluation");
69 
70  Parent::resize_data_structures(Nmax, resize_error_bound_data);
71 
72  RB_L2_matrix.resize(Nmax,Nmax);
73  RB_LHS_matrix.resize(Nmax,Nmax);
74  RB_RHS_matrix.resize(Nmax,Nmax);
75  RB_RHS_save.resize(Nmax);
76 
77  TransientRBThetaExpansion & trans_theta_expansion =
78  cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
79  const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
80  const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
81  const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
82 
83  // Allocate dense matrices for RB solves
84  RB_M_q_vector.resize(Q_m);
85  for (unsigned int q=0; q<Q_m; q++)
86  {
87  // Initialize the memory for the RB matrices
88  RB_M_q_vector[q].resize(Nmax,Nmax);
89  }
90 
91  // Initialize the initial condition storage
92  RB_initial_condition_all_N.resize(Nmax);
93  for (auto i : make_range(RB_initial_condition_all_N.size()))
94  {
95  // The i^th row holds a vector of length i+1
96  RB_initial_condition_all_N[i].resize(i+1);
97  }
98 
99  initial_L2_error_all_N.resize(Nmax, 0.);
100 
101 
102  if (resize_error_bound_data)
103  {
104  // Initialize vectors for the norms of the representors
105  Fq_Mq_representor_innerprods.resize(Q_f);
106  for (unsigned int i=0; i<Q_f; i++)
107  {
108  Fq_Mq_representor_innerprods[i].resize(Q_m);
109  for (unsigned int j=0; j<Q_m; j++)
110  {
111  Fq_Mq_representor_innerprods[i][j].resize(Nmax, 0.);
112  }
113  }
114 
115  unsigned int Q_m_hat = Q_m*(Q_m+1)/2;
116  Mq_Mq_representor_innerprods.resize(Q_m_hat);
117  for (unsigned int i=0; i<Q_m_hat; i++)
118  {
119  Mq_Mq_representor_innerprods[i].resize(Nmax);
120  for (unsigned int j=0; j<Nmax; j++)
121  {
122  Mq_Mq_representor_innerprods[i][j].resize(Nmax, 0.);
123  }
124  }
125 
126  Aq_Mq_representor_innerprods.resize(Q_a);
127  for (unsigned int i=0; i<Q_a; i++)
128  {
129  Aq_Mq_representor_innerprods[i].resize(Q_m);
130  for (unsigned int j=0; j<Q_m; j++)
131  {
132  Aq_Mq_representor_innerprods[i][j].resize(Nmax);
133  for (unsigned int k=0; k<Nmax; k++)
134  {
135  Aq_Mq_representor_innerprods[i][j][k].resize(Nmax, 0.);
136  }
137  }
138  }
139 
140  // Resize M_q_representor
141  // This is cleared in the call to clear_riesz_representors
142  // in Parent::resize_RB_data, so just resize here
143  M_q_representor.resize(Q_m);
144  for (unsigned int q_m=0; q_m<Q_m; q_m++)
145  {
146  M_q_representor[q_m].resize(Nmax);
147  }
148  }
149 }
150 
152 {
153  LOG_SCOPE("rb_solve()", "TransientRBEvaluation");
154 
155  libmesh_error_msg_if(N > get_n_basis_functions(),
156  "ERROR: N cannot be larger than the number of basis functions in rb_solve");
157 
158  const RBParameters & mu = get_parameters();
159 
160  TransientRBThetaExpansion & trans_theta_expansion =
161  cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
162  const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
163  const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
164  const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
165 
166  const unsigned int n_time_steps = get_n_time_steps();
167  const Real dt = get_delta_t();
168  const Real euler_theta = get_euler_theta();
169 
170  // Resize the RB and error bound vectors
171  error_bound_all_k.resize(n_time_steps+1);
172  RB_outputs_all_k.resize(trans_theta_expansion.get_n_outputs());
173  RB_output_error_bounds_all_k.resize(trans_theta_expansion.get_n_outputs());
174  for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
175  {
176  RB_outputs_all_k[n].resize(n_time_steps+1, 0.);
177  RB_output_error_bounds_all_k[n].resize(n_time_steps+1, 0.);
178  }
179 
180  // First assemble the mass matrix
181  DenseMatrix<Number> RB_mass_matrix_N(N,N);
182  RB_mass_matrix_N.zero();
183  DenseMatrix<Number> RB_M_q_m;
184  for (unsigned int q_m=0; q_m<Q_m; q_m++)
185  {
186  RB_M_q_vector[q_m].get_principal_submatrix(N, RB_M_q_m);
187  RB_mass_matrix_N.add(trans_theta_expansion.eval_M_theta(q_m, mu), RB_M_q_m);
188  }
189 
190  RB_LHS_matrix.resize(N,N);
192 
193  RB_RHS_matrix.resize(N,N);
195 
196  RB_LHS_matrix.add(1./dt, RB_mass_matrix_N);
197  RB_RHS_matrix.add(1./dt, RB_mass_matrix_N);
198 
199  DenseMatrix<Number> RB_Aq_a;
200  for (unsigned int q_a=0; q_a<Q_a; q_a++)
201  {
202  RB_Aq_vector[q_a].get_principal_submatrix(N, RB_Aq_a);
203 
204  RB_LHS_matrix.add( euler_theta*trans_theta_expansion.eval_A_theta(q_a,mu), RB_Aq_a);
205  RB_RHS_matrix.add( -(1.-euler_theta)*trans_theta_expansion.eval_A_theta(q_a,mu), RB_Aq_a);
206  }
207 
208  // Add forcing terms
209  DenseVector<Number> RB_Fq_f;
210  RB_RHS_save.resize(N);
211  RB_RHS_save.zero();
212  for (unsigned int q_f=0; q_f<Q_f; q_f++)
213  {
214  RB_Fq_vector[q_f].get_principal_subvector(N, RB_Fq_f);
215  RB_RHS_save.add(trans_theta_expansion.eval_F_theta(q_f,mu), RB_Fq_f);
216  }
217 
218  // Set system time level to 0
219  set_time_step(0);
220 
221  // Resize/clear the solution vector
222  RB_solution.resize(N);
223 
224  // Load the initial condition into RB_solution
225  if (N > 0)
226  {
228  }
229 
230  // Resize/clear the old solution vector
232 
233  // Initialize the RB rhs
234  DenseVector<Number> RB_rhs(N);
235  RB_rhs.zero();
236 
237  // Initialize the vectors storing solution data
238  RB_temporal_solution_data.resize(n_time_steps+1);
239  for (unsigned int time_level=0; time_level<=n_time_steps; time_level++)
240  {
241  RB_temporal_solution_data[time_level].resize(N);
242  }
243  // and load the initial data
245 
246  // Set outputs at initial time
247  {
248  DenseVector<Number> RB_output_vector_N;
249  for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
250  {
251  RB_outputs_all_k[n][0] = 0.;
252  for (unsigned int q_l=0; q_l<trans_theta_expansion.get_n_output_terms(n); q_l++)
253  {
254  RB_output_vectors[n][q_l].get_principal_subvector(N, RB_output_vector_N);
255  RB_outputs_all_k[n][0] += trans_theta_expansion.eval_output_theta(n,q_l,mu)*RB_output_vector_N.dot(RB_solution);
256  }
257  }
258  }
259 
260  // Initialize error bounds, if necessary
261  Real error_bound_sum = 0.;
262  Real alpha_LB = 0.;
264  {
265  if (N > 0)
266  {
267  error_bound_sum += pow( initial_L2_error_all_N[N-1], 2.);
268  }
269 
270  // Set error bound at the initial time
271  error_bound_all_k[get_time_step()] = std::sqrt(error_bound_sum);
272 
273  // Compute the outputs and associated error bounds at the initial time
274  DenseVector<Number> RB_output_vector_N;
275  for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
276  {
277  RB_outputs_all_k[n][0] = 0.;
278  for (unsigned int q_l=0; q_l<trans_theta_expansion.get_n_output_terms(n); q_l++)
279  {
280  RB_output_vectors[n][q_l].get_principal_subvector(N, RB_output_vector_N);
281  RB_outputs_all_k[n][0] += trans_theta_expansion.eval_output_theta(n,q_l,mu)*RB_output_vector_N.dot(RB_solution);
282  }
283 
285  }
286 
287  alpha_LB = get_stability_lower_bound();
288 
289  // Precompute time-invariant parts of the dual norm of the residual.
291  }
292 
293  for (unsigned int time_level=1; time_level<=n_time_steps; time_level++)
294  {
295  set_time_step(time_level);
297 
298  // Compute RB_rhs, as RB_LHS_matrix x old_RB_solution
300 
301  // Add forcing terms
302  RB_rhs.add(get_control(time_level), RB_RHS_save);
303 
304  if (N > 0)
305  {
307  }
308 
309  // Save RB_solution for current time level
311 
312  // Evaluate outputs
313  DenseVector<Number> RB_output_vector_N;
314  for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
315  {
316  RB_outputs_all_k[n][time_level] = 0.;
317  for (unsigned int q_l=0; q_l<trans_theta_expansion.get_n_output_terms(n); q_l++)
318  {
319  RB_output_vectors[n][q_l].get_principal_subvector(N, RB_output_vector_N);
320  RB_outputs_all_k[n][time_level] += trans_theta_expansion.eval_output_theta(n,q_l,mu)*
321  RB_output_vector_N.dot(RB_solution);
322  }
323  }
324 
325  // Calculate RB error bounds
327  {
328  // Evaluate the dual norm of the residual for RB_solution_vector
329  // Real epsilon_N = uncached_compute_residual_dual_norm(N);
330  Real epsilon_N = compute_residual_dual_norm(N);
331 
332  error_bound_sum += residual_scaling_numer(alpha_LB) * pow(epsilon_N, 2.);
333 
334  // store error bound at time-level _k
335  error_bound_all_k[time_level] = std::sqrt(error_bound_sum/residual_scaling_denom(alpha_LB));
336 
337  // Now evaluated output error bounds
338  for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
339  {
340  RB_output_error_bounds_all_k[n][time_level] = error_bound_all_k[time_level] *
341  eval_output_dual_norm(n, nullptr);
342  }
343  }
344  }
345 
346  _rb_solve_data_cached = true ;
347 
348  if (evaluate_RB_error_bound) // Calculate the error bounds
349  {
350  return error_bound_all_k[n_time_steps];
351  }
352  else // Don't calculate the error bounds
353  {
354  // Just return -1. if we did not compute the error bound
355  return -1.;
356  }
357 }
358 
360 {
362 
363  const unsigned int n_time_steps = get_n_time_steps();
364  // Set system time level to 0
365  set_time_step(0);
366 
367  // Resize/clear the solution vector
368  const unsigned int N = RB_RHS_save.size();
369  RB_solution.resize(N);
370 
371  // Load the initial condition into RB_solution
372  if (N > 0)
374 
375  // Resize/clear the old solution vector
377 
378  // Initialize the RB rhs
379  DenseVector<Number> RB_rhs(N);
380  RB_rhs.zero();
381 
382  for (unsigned int time_level=1; time_level<=n_time_steps; time_level++)
383  {
384  set_time_step(time_level);
386 
387  // Compute RB_rhs, as *RB_lhs_matrix x old_RB_solution
389 
390  // Add forcing terms
391  RB_rhs.add(get_control(time_level), RB_RHS_save);
392 
393  if (N > 0)
395  }
396 
397  {
398  // Just return -1. We did not compute the error bound
399  return -1.;
400  }
401 }
402 
404 {
405  // Just set the normalization factor to 1 in this case.
406  // Users can override this method if specific behavior
407  // is required.
408 
409  return 1.;
410 }
411 
413 {
414  return get_delta_t();
415 }
416 
418 {
419  LOG_SCOPE("cache_online_residual_terms()", "TransientRBEvaluation");
420 
421  const RBParameters mu = get_parameters();
422 
423  TransientRBThetaExpansion & trans_theta_expansion =
424  cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
425  const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
426  const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
427  const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
428 
429  cached_Fq_term = 0.;
430  unsigned int q=0;
431  for (unsigned int q_f1=0; q_f1<Q_f; q_f1++)
432  {
433  Number cached_theta_q_f1 = trans_theta_expansion.eval_F_theta(q_f1,mu);
434  for (unsigned int q_f2=q_f1; q_f2<Q_f; q_f2++)
435  {
436  Real delta = (q_f1==q_f2) ? 1. : 2.;
437  cached_Fq_term += delta*cached_theta_q_f1*trans_theta_expansion.eval_F_theta(q_f2,mu) *
439 
440  q++;
441  }
442  }
443 
445  for (unsigned int q_f=0; q_f<Q_f; q_f++)
446  {
447  Number cached_theta_q_f = trans_theta_expansion.eval_F_theta(q_f,mu);
448  for (unsigned int q_a=0; q_a<Q_a; q_a++)
449  {
450  Number cached_theta_q_a = trans_theta_expansion.eval_A_theta(q_a,mu);
451  for (unsigned int i=0; i<N; i++)
452  {
453  cached_Fq_Aq_vector(i) += 2.*cached_theta_q_f*cached_theta_q_a*
454  Fq_Aq_representor_innerprods[q_f][q_a][i];
455  }
456  }
457  }
458 
460  q=0;
461  for (unsigned int q_a1=0; q_a1<Q_a; q_a1++)
462  {
463  Number cached_theta_q_a1 = trans_theta_expansion.eval_A_theta(q_a1,mu);
464  for (unsigned int q_a2=q_a1; q_a2<Q_a; q_a2++)
465  {
466  Number cached_theta_q_a2 = trans_theta_expansion.eval_A_theta(q_a2,mu);
467  Real delta = (q_a1==q_a2) ? 1. : 2.;
468 
469  for (unsigned int i=0; i<N; i++)
470  {
471  for (unsigned int j=0; j<N; j++)
472  {
473  cached_Aq_Aq_matrix(i,j) += delta*
474  cached_theta_q_a1*cached_theta_q_a2*
476  }
477  }
478  q++;
479  }
480  }
481 
483  for (unsigned int q_f=0; q_f<Q_f; q_f++)
484  {
485  Number cached_theta_q_f = trans_theta_expansion.eval_F_theta(q_f,mu);
486  for (unsigned int q_m=0; q_m<Q_m; q_m++)
487  {
488  Number cached_theta_q_m = trans_theta_expansion.eval_M_theta(q_m,mu);
489  for (unsigned int i=0; i<N; i++)
490  {
491  cached_Fq_Mq_vector(i) += 2.*cached_theta_q_f * cached_theta_q_m * Fq_Mq_representor_innerprods[q_f][q_m][i];
492  }
493  }
494  }
495 
497  for (unsigned int q_a=0; q_a<Q_a; q_a++)
498  {
499  Number cached_theta_q_a = trans_theta_expansion.eval_A_theta(q_a,mu);
500 
501  for (unsigned int q_m=0; q_m<Q_m; q_m++)
502  {
503  Number cached_theta_q_m = trans_theta_expansion.eval_M_theta(q_m,mu);
504 
505  for (unsigned int i=0; i<N; i++)
506  {
507  for (unsigned int j=0; j<N; j++)
508  {
509  cached_Aq_Mq_matrix(i,j) += 2.*cached_theta_q_a*cached_theta_q_m*Aq_Mq_representor_innerprods[q_a][q_m][i][j];
510  }
511  }
512  }
513  }
514 
516  q=0;
517  for (unsigned int q_m1=0; q_m1<Q_m; q_m1++)
518  {
519  Number cached_theta_q_m1 = trans_theta_expansion.eval_M_theta(q_m1,mu);
520  for (unsigned int q_m2=q_m1; q_m2<Q_m; q_m2++)
521  {
522  Number cached_theta_q_m2 = trans_theta_expansion.eval_M_theta(q_m2,mu);
523  Real delta = (q_m1==q_m2) ? 1. : 2.;
524 
525  for (unsigned int i=0; i<N; i++)
526  {
527  for (unsigned int j=0; j<N; j++)
528  {
529  cached_Mq_Mq_matrix(i,j) += delta*
530  cached_theta_q_m1*cached_theta_q_m2*
532  }
533  }
534  q++;
535  }
536  }
537 }
538 
540 {
541  LOG_SCOPE("compute_residual_dual_norm()", "TransientRBEvaluation");
542 
543  // This assembly assumes we have already called cache_online_residual_terms
544  // and that the rb_solve parameter is constant in time
545 
546  const Real dt = get_delta_t();
547  const Real euler_theta = get_euler_theta();
548  const Real current_control = get_control(get_time_step());
549 
550  DenseVector<Number> RB_u_euler_theta(N);
551  DenseVector<Number> mass_coeffs(N);
552  for (unsigned int i=0; i<N; i++)
553  {
554  RB_u_euler_theta(i) = euler_theta*RB_solution(i) +
555  (1.-euler_theta)*old_RB_solution(i);
556  mass_coeffs(i) = -(RB_solution(i) - old_RB_solution(i))/dt;
557  }
558 
559  Number residual_norm_sq = current_control*current_control*cached_Fq_term;
560 
561  residual_norm_sq += current_control*RB_u_euler_theta.dot(cached_Fq_Aq_vector);
562  residual_norm_sq += current_control*mass_coeffs.dot(cached_Fq_Mq_vector);
563 
564  for (unsigned int i=0; i<N; i++)
565  for (unsigned int j=0; j<N; j++)
566  {
567  residual_norm_sq += RB_u_euler_theta(i)*RB_u_euler_theta(j)*cached_Aq_Aq_matrix(i,j);
568  residual_norm_sq += mass_coeffs(i)*mass_coeffs(j)*cached_Mq_Mq_matrix(i,j);
569  residual_norm_sq += RB_u_euler_theta(i)*mass_coeffs(j)*cached_Aq_Mq_matrix(i,j);
570  }
571 
572 
573  if (libmesh_real(residual_norm_sq) < 0)
574  {
575  libMesh::out << "Warning: Square of residual norm is negative "
576  << "in TransientRBEvaluation::compute_residual_dual_norm()" << std::endl;
577 
578  // Sometimes this is negative due to rounding error,
579  // but error is on the order of 1.e-10, so shouldn't
580  // affect result
581  residual_norm_sq = std::abs(residual_norm_sq);
582  }
583 
584  return libmesh_real(std::sqrt( residual_norm_sq ));
585 }
586 
588 {
589  LOG_SCOPE("uncached_compute_residual_dual_norm()", "TransientRBEvaluation");
590 
591  // Use the stored representor inner product values
592  // to evaluate the residual norm
593 
594  const RBParameters & mu = get_parameters();
595 
596  TransientRBThetaExpansion & trans_theta_expansion =
597  cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
598  const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
599  const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
600  const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
601 
602  const Real dt = get_delta_t();
603  const Real euler_theta = get_euler_theta();
604 
605  std::vector<Number> RB_u_euler_theta(N);
606  std::vector<Number> mass_coeffs(N);
607  for (unsigned int i=0; i<N; i++)
608  {
609  RB_u_euler_theta[i] = euler_theta*RB_solution(i) +
610  (1.-euler_theta)*old_RB_solution(i);
611  mass_coeffs[i] = -(RB_solution(i) - old_RB_solution(i))/dt;
612  }
613 
614  Number residual_norm_sq = 0.;
615 
616  unsigned int q=0;
617  for (unsigned int q_f1=0; q_f1<Q_f; q_f1++)
618  {
619  Number cached_theta_q_f1 = trans_theta_expansion.eval_F_theta(q_f1,mu);
620  for (unsigned int q_f2=q_f1; q_f2<Q_f; q_f2++)
621  {
622  Real delta = (q_f1==q_f2) ? 1. : 2.;
623  residual_norm_sq += delta*cached_theta_q_f1*trans_theta_expansion.eval_F_theta(q_f2,mu) * Fq_representor_innerprods[q];
624 
625  q++;
626  }
627  }
628 
629  for (unsigned int q_f=0; q_f<Q_f; q_f++)
630  {
631  Number cached_theta_q_f = trans_theta_expansion.eval_F_theta(q_f,mu);
632  for (unsigned int q_a=0; q_a<Q_a; q_a++)
633  {
634  Number cached_theta_q_a = trans_theta_expansion.eval_A_theta(q_a,mu);
635  for (unsigned int i=0; i<N; i++)
636  {
637  residual_norm_sq += 2.*RB_u_euler_theta[i]*cached_theta_q_f*cached_theta_q_a*
638  Fq_Aq_representor_innerprods[q_f][q_a][i];
639  }
640  }
641  }
642 
643  q=0;
644  for (unsigned int q_a1=0; q_a1<Q_a; q_a1++)
645  {
646  Number cached_theta_q_a1 = trans_theta_expansion.eval_A_theta(q_a1,mu);
647  for (unsigned int q_a2=q_a1; q_a2<Q_a; q_a2++)
648  {
649  Number cached_theta_q_a2 = trans_theta_expansion.eval_A_theta(q_a2,mu);
650  Real delta = (q_a1==q_a2) ? 1. : 2.;
651 
652  for (unsigned int i=0; i<N; i++)
653  {
654  for (unsigned int j=0; j<N; j++)
655  {
656  residual_norm_sq += delta*RB_u_euler_theta[i]*RB_u_euler_theta[j]*
657  cached_theta_q_a1*cached_theta_q_a2*
659  }
660  }
661  q++;
662  }
663  }
664 
665  // Now add the terms due to the time-derivative
666  q=0;
667  for (unsigned int q_m1=0; q_m1<Q_m; q_m1++)
668  {
669  Number cached_theta_q_m1 = trans_theta_expansion.eval_M_theta(q_m1,mu);
670  for (unsigned int q_m2=q_m1; q_m2<Q_m; q_m2++)
671  {
672  Number cached_theta_q_m2 = trans_theta_expansion.eval_M_theta(q_m2,mu);
673  Real delta = (q_m1==q_m2) ? 1. : 2.;
674 
675  for (unsigned int i=0; i<N; i++)
676  {
677  for (unsigned int j=0; j<N; j++)
678  {
679  residual_norm_sq += delta*mass_coeffs[i]*mass_coeffs[j]*
680  cached_theta_q_m1*cached_theta_q_m2*
682  }
683  }
684  q++;
685  }
686  }
687 
688  for (unsigned int q_f=0; q_f<Q_f; q_f++)
689  {
690  Number cached_theta_q_f = trans_theta_expansion.eval_F_theta(q_f,mu);
691  for (unsigned int q_m=0; q_m<Q_m; q_m++)
692  {
693  Number cached_theta_q_m = trans_theta_expansion.eval_M_theta(q_m,mu);
694  for (unsigned int i=0; i<N; i++)
695  {
696  residual_norm_sq += 2.*mass_coeffs[i]*cached_theta_q_f * cached_theta_q_m * Fq_Mq_representor_innerprods[q_f][q_m][i];
697  }
698  }
699  }
700 
701  for (unsigned int q_a=0; q_a<Q_a; q_a++)
702  {
703  Number cached_theta_q_a = trans_theta_expansion.eval_A_theta(q_a,mu);
704 
705  for (unsigned int q_m=0; q_m<Q_m; q_m++)
706  {
707  Number cached_theta_q_m = trans_theta_expansion.eval_M_theta(q_m,mu);
708 
709  for (unsigned int i=0; i<N; i++)
710  {
711  for (unsigned int j=0; j<N; j++)
712  {
713  residual_norm_sq += 2.*RB_u_euler_theta[i]*mass_coeffs[j]*
714  cached_theta_q_a*cached_theta_q_m*
715  Aq_Mq_representor_innerprods[q_a][q_m][i][j];
716  }
717  }
718  }
719  }
720 
721  if (libmesh_real(residual_norm_sq) < 0)
722  {
723  libMesh::out << "Warning: Square of residual norm is negative "
724  << "in TransientRBEvaluation::compute_residual_dual_norm()" << std::endl;
725 
726  // Sometimes this is negative due to rounding error,
727  // but error is on the order of 1.e-10, so shouldn't
728  // affect result
729  residual_norm_sq = std::abs(residual_norm_sq);
730  }
731 
732  // libMesh::out << "slow residual_sq = " << slow_residual_norm_sq
733  // << ", fast residual_sq = " << residual_norm_sq << std::endl;
734 
735  return libmesh_real(std::sqrt( residual_norm_sq ));
736 }
737 
738 void TransientRBEvaluation::legacy_write_offline_data_to_files(const std::string & directory_name,
739  const bool write_binary_data)
740 {
741  LOG_SCOPE("legacy_write_offline_data_to_files()", "TransientRBEvaluation");
742 
744 
745  TransientRBThetaExpansion & trans_theta_expansion =
746  cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
747  const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
748  const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
749  const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
750 
751  const unsigned int n_bfs = get_n_basis_functions();
752 
753  // The writing mode: ENCODE for binary, WRITE for ASCII
754  XdrMODE mode = write_binary_data ? ENCODE : WRITE;
755 
756  // The suffix to use for all the files that are written out
757  const std::string suffix = write_binary_data ? ".xdr" : ".dat";
758 
759  if (this->processor_id() == 0)
760  {
761  std::ostringstream file_name;
762 
763  // Write out the temporal discretization data
764  file_name.str("");
765  file_name << directory_name << "/temporal_discretization_data" << suffix;
766  Xdr temporal_discretization_data_out(file_name.str(), mode);
767 
768  Real real_value; unsigned int int_value;
769  real_value = get_delta_t(); temporal_discretization_data_out << real_value;
770  real_value = get_euler_theta(); temporal_discretization_data_out << real_value;
771  int_value = get_n_time_steps(); temporal_discretization_data_out << int_value;
772  int_value = get_time_step(); temporal_discretization_data_out << int_value;
773  temporal_discretization_data_out.close();
774 
775 
776  // Write out the L2 matrix
777  file_name.str("");
778  file_name << directory_name << "/RB_L2_matrix" << suffix;
779  Xdr RB_L2_matrix_out(file_name.str(), mode);
780 
781  for (unsigned int i=0; i<n_bfs; i++)
782  {
783  for (unsigned int j=0; j<n_bfs; j++)
784  {
785  RB_L2_matrix_out << RB_L2_matrix(i,j);
786  }
787  }
788  RB_L2_matrix_out.close();
789 
790  // Write out the M_q matrices
791  for (unsigned int q_m=0; q_m<Q_m; q_m++)
792  {
793  file_name.str("");
794  file_name << directory_name << "/RB_M_";
795  file_name << std::setw(3)
796  << std::setprecision(0)
797  << std::setfill('0')
798  << std::right
799  << q_m;
800  file_name << suffix;
801  Xdr RB_M_q_m_out(file_name.str(), mode);
802 
803  for (unsigned int i=0; i<n_bfs; i++)
804  {
805  for (unsigned int j=0; j<n_bfs; j++)
806  {
807  RB_M_q_m_out << RB_M_q_vector[q_m](i,j);
808  }
809  }
810  RB_M_q_m_out.close();
811  }
812 
813  // Write out the initial condition data
814  // and the initial L2 error for all N
815  file_name.str("");
816  file_name << directory_name << "/initial_conditions" << suffix;
817  Xdr initial_conditions_out(file_name.str(), mode);
818  file_name.str("");
819  file_name << directory_name << "/initial_L2_error" << suffix;
820  Xdr initial_L2_error_out(file_name.str(), mode);
821 
822  for (unsigned int i=0; i<n_bfs; i++)
823  {
824  initial_L2_error_out << initial_L2_error_all_N[i];
825  for (unsigned int j=0; j<=i; j++)
826  {
827  initial_conditions_out << RB_initial_condition_all_N[i](j);
828  }
829  }
830  initial_conditions_out.close();
831  initial_L2_error_out.close();
832 
833  // Next write out the Fq_Mq representor norm data
834  file_name.str("");
835  file_name << directory_name << "/Fq_Mq_terms" << suffix;
836  Xdr RB_Fq_Mq_terms_out(file_name.str(), mode);
837 
838  for (unsigned int q_f=0; q_f<Q_f; q_f++)
839  {
840  for (unsigned int q_m=0; q_m<Q_m; q_m++)
841  {
842  for (unsigned int i=0; i<n_bfs; i++)
843  {
844  RB_Fq_Mq_terms_out << Fq_Mq_representor_innerprods[q_f][q_m][i];
845  }
846  }
847  }
848  RB_Fq_Mq_terms_out.close();
849 
850  // Next write out the Mq_Mq representor norm data
851  file_name.str("");
852  file_name << directory_name << "/Mq_Mq_terms" << suffix;
853  Xdr RB_Mq_Mq_terms_out(file_name.str(), mode);
854 
855  unsigned int Q_m_hat = Q_m*(Q_m+1)/2;
856  for (unsigned int q=0; q<Q_m_hat; q++)
857  {
858  for (unsigned int i=0; i<n_bfs; i++)
859  {
860  for (unsigned int j=0; j<n_bfs; j++)
861  {
862  RB_Mq_Mq_terms_out << Mq_Mq_representor_innerprods[q][i][j];
863  }
864  }
865  }
866  RB_Mq_Mq_terms_out.close();
867 
868  // Next write out the Aq_Mq representor norm data
869  file_name.str("");
870  file_name << directory_name << "/Aq_Mq_terms" << suffix;
871  Xdr RB_Aq_Mq_terms_out(file_name.str(), mode);
872 
873  for (unsigned int q_a=0; q_a<Q_a; q_a++)
874  {
875  for (unsigned int q_m=0; q_m<Q_m; q_m++)
876  {
877  for (unsigned int i=0; i<n_bfs; i++)
878  {
879  for (unsigned int j=0; j<n_bfs; j++)
880  {
881  RB_Aq_Mq_terms_out << Aq_Mq_representor_innerprods[q_a][q_m][i][j];
882  }
883  }
884  }
885  }
886  RB_Aq_Mq_terms_out.close();
887  }
888 }
889 
890 void TransientRBEvaluation::legacy_read_offline_data_from_files(const std::string & directory_name,
891  bool read_error_bound_data,
892  const bool read_binary_data)
893 {
894  LOG_SCOPE("legacy_read_offline_data_from_files()", "TransientRBEvaluation");
895 
897 
898  TransientRBThetaExpansion & trans_theta_expansion =
899  cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
900  const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
901  const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
902  const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
903 
904  // First, find out how many basis functions we had when Greedy terminated
905  // This was set in RBSystem::read_offline_data_from_files
906  unsigned int n_bfs = this->get_n_basis_functions();
907 
908  // The reading mode: DECODE for binary, READ for ASCII
909  XdrMODE mode = read_binary_data ? DECODE : READ;
910 
911  // The suffix to use for all the files that are written out
912  const std::string suffix = read_binary_data ? ".xdr" : ".dat";
913 
914  // The string stream we'll use to make the file names
915  std::ostringstream file_name;
916 
917  // Write out the temporal discretization data
918  file_name.str("");
919  file_name << directory_name << "/temporal_discretization_data" << suffix;
920  assert_file_exists(file_name.str());
921 
922  Xdr temporal_discretization_data_in(file_name.str(), mode);
923 
924  Real real_value; unsigned int int_value;
925  temporal_discretization_data_in >> real_value; set_delta_t(real_value);
926  temporal_discretization_data_in >> real_value; set_euler_theta(real_value);
927  temporal_discretization_data_in >> int_value; set_n_time_steps(int_value);
928  temporal_discretization_data_in >> int_value; set_time_step(int_value);
929  temporal_discretization_data_in.close();
930 
931  file_name.str("");
932  file_name << directory_name << "/RB_L2_matrix" << suffix;
933  assert_file_exists(file_name.str());
934 
935  Xdr RB_L2_matrix_in(file_name.str(), mode);
936 
937  for (unsigned int i=0; i<n_bfs; i++)
938  {
939  for (unsigned int j=0; j<n_bfs; j++)
940  {
941  Number value;
942  RB_L2_matrix_in >> value;
943  RB_L2_matrix(i,j) = value;
944  }
945  }
946  RB_L2_matrix_in.close();
947 
948  // Read in the M_q matrices
949  for (unsigned int q_m=0; q_m<Q_m; q_m++)
950  {
951  file_name.str("");
952  file_name << directory_name << "/RB_M_";
953  file_name << std::setw(3)
954  << std::setprecision(0)
955  << std::setfill('0')
956  << std::right
957  << q_m;
958 
959  file_name << suffix;
960  assert_file_exists(file_name.str());
961 
962  Xdr RB_M_q_m_in(file_name.str(), mode);
963 
964  for (unsigned int i=0; i<n_bfs; i++)
965  {
966  for (unsigned int j=0; j<n_bfs; j++)
967  {
968  Number value;
969  RB_M_q_m_in >> value;
970  RB_M_q_vector[q_m](i,j) = value;
971  }
972  }
973  RB_M_q_m_in.close();
974  }
975 
976 
977  // Read in the initial condition data
978  // and the initial L2 error for all N
979  file_name.str("");
980  file_name << directory_name << "/initial_conditions" << suffix;
981  assert_file_exists(file_name.str());
982 
983  Xdr initial_conditions_in(file_name.str(), mode);
984 
985  file_name.str("");
986  file_name << directory_name << "/initial_L2_error" << suffix;
987  assert_file_exists(file_name.str());
988 
989  Xdr initial_L2_error_in(file_name.str(), mode);
990 
991  for (unsigned int i=0; i<n_bfs; i++)
992  {
993  initial_L2_error_in >> initial_L2_error_all_N[i];
994  for (unsigned int j=0; j<=i; j++)
995  {
996  initial_conditions_in >> RB_initial_condition_all_N[i](j);
997  }
998  }
999  initial_conditions_in.close();
1000  initial_L2_error_in.close();
1001 
1002 
1003  if (read_error_bound_data)
1004  {
1005  // Next read in the Fq_Mq representor norm data
1006  file_name.str("");
1007  file_name << directory_name << "/Fq_Mq_terms" << suffix;
1008  assert_file_exists(file_name.str());
1009 
1010  Xdr RB_Fq_Mq_terms_in(file_name.str(), mode);
1011 
1012  for (unsigned int q_f=0; q_f<Q_f; q_f++)
1013  {
1014  for (unsigned int q_m=0; q_m<Q_m; q_m++)
1015  {
1016  for (unsigned int i=0; i<n_bfs; i++)
1017  {
1018  RB_Fq_Mq_terms_in >> Fq_Mq_representor_innerprods[q_f][q_m][i];
1019  }
1020  }
1021  }
1022  RB_Fq_Mq_terms_in.close();
1023 
1024  // Next read in the Mq_Mq representor norm data
1025  file_name.str("");
1026  file_name << directory_name << "/Mq_Mq_terms" << suffix;
1027  assert_file_exists(file_name.str());
1028 
1029  Xdr RB_Mq_Mq_terms_in(file_name.str(), mode);
1030 
1031  unsigned int Q_m_hat = Q_m*(Q_m+1)/2;
1032  for (unsigned int q=0; q<Q_m_hat; q++)
1033  {
1034  for (unsigned int i=0; i<n_bfs; i++)
1035  {
1036  for (unsigned int j=0; j<n_bfs; j++)
1037  {
1038  RB_Mq_Mq_terms_in >> Mq_Mq_representor_innerprods[q][i][j];
1039  }
1040  }
1041  }
1042  RB_Mq_Mq_terms_in.close();
1043 
1044  // Next read in the Aq_Mq representor norm data
1045  file_name.str("");
1046  file_name << directory_name << "/Aq_Mq_terms" << suffix;
1047  assert_file_exists(file_name.str());
1048 
1049  Xdr RB_Aq_Mq_terms_in(file_name.str(), mode);
1050 
1051  for (unsigned int q_a=0; q_a<Q_a; q_a++)
1052  {
1053  for (unsigned int q_m=0; q_m<Q_m; q_m++)
1054  {
1055  for (unsigned int i=0; i<n_bfs; i++)
1056  {
1057  for (unsigned int j=0; j<n_bfs; j++)
1058  {
1059  RB_Aq_Mq_terms_in >> Aq_Mq_representor_innerprods[q_a][q_m][i][j];
1060  }
1061  }
1062  }
1063  }
1064  RB_Aq_Mq_terms_in.close();
1065  }
1066 }
1067 
1068 }
T libmesh_real(T a)
std::vector< std::vector< std::vector< Number > > > Mq_Mq_representor_innerprods
bool compute_RB_inner_product
Boolean flag to indicate whether we compute the RB_inner_product_matrix.
virtual void resize_data_structures(const unsigned int Nmax, bool resize_error_bound_data=true) override
Resize and clear the data vectors corresponding to the value of Nmax.
virtual Number eval_output_theta(unsigned int output_index, unsigned int q_l, const RBParameters &mu) const
Evaluate theta_q_l at the current parameter.
virtual Number eval_A_theta(unsigned int q, const RBParameters &mu) const
Evaluate theta_q_a at the current parameter.
bool evaluate_RB_error_bound
Boolean to indicate whether we evaluate a posteriori error bounds when rb_solve is called...
boostcopy::enable_if_c< ScalarTraits< T2 >::value, void >::type add(const T2 factor, const DenseVector< T3 > &vec)
Adds factor times vec to this vector.
Definition: dense_vector.h:477
std::vector< Number > Fq_representor_innerprods
Vectors storing the residual representor inner products to be used in computing the residuals online...
virtual void zero() override final
Set every element in the vector to 0.
Definition: dense_vector.h:420
unsigned int get_n_F_terms() const
Get Q_f, the number of terms in the affine expansion for the right-hand side.
virtual Real uncached_compute_residual_dual_norm(const unsigned int N)
Compute the dual norm of the residual for the solution saved in RB_solution.
virtual void resize_data_structures(const unsigned int Nmax, bool resize_error_bound_data=true)
Resize and clear the data vectors corresponding to the value of Nmax.
DenseVector< Number > RB_solution
The RB solution vector.
Number cached_Fq_term
Cached residual terms.
DenseMatrix< Number > RB_LHS_matrix
Cached data for subsequent solves.
virtual void zero() override final
Sets all elements of the matrix to 0 and resets any decomposition flag which may have been previously...
Definition: dense_matrix.h:911
virtual void clear_riesz_representors() override
Clear all the Riesz representors that are used to compute the RB residual (and hence error bound)...
std::vector< DenseMatrix< Number > > RB_M_q_vector
Dense matrices for the RB mass matrices.
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:396
void cache_online_residual_terms(const unsigned int N)
Helper function for caching the terms in the online residual assembly that do not change in time...
DenseVector< Number > old_RB_solution
The RB solution at the previous time-level.
unsigned int get_n_A_terms() const
Get Q_a, the number of terms in the affine expansion for the bilinear form.
virtual Real compute_residual_dual_norm(const unsigned int N) override
Compute the dual norm of the residual for the solution saved in RB_solution_vector.
This class stores the set of RBTheta functor objects that define the "parameter-dependent expansion" ...
The libMesh namespace provides an interface to certain functionality in the library.
virtual Number eval_M_theta(unsigned int q, const RBParameters &mu) const
Evaluate theta at the current parameter.
Real get_delta_t() const
Get/set delta_t, the time-step size.
unsigned int get_n_outputs() const
Get n_outputs, the number output functionals.
virtual Real get_error_bound_normalization() override
Real get_euler_theta() const
Get/set euler_theta, parameter that determines the temporal discretization.
XdrMODE
Defines an enum for read/write mode in Xdr format.
Definition: enum_xdr_mode.h:35
std::vector< DenseVector< Number > > RB_Fq_vector
Dense vector for the RHS.
std::vector< std::vector< std::unique_ptr< NumericVector< Number > > > > M_q_representor
Vector storing the mass matrix representors.
virtual void legacy_write_offline_data_to_files(const std::string &directory_name="offline_data", const bool write_binary_data=true) override
Write out all the data to text files in order to segregate the Offline stage from the Online stage...
bool _rb_solve_data_cached
Check that the data has been cached in case of using rb_solve_again.
T pow(const T &x)
Definition: utility.h:328
std::vector< Real > initial_L2_error_all_N
Vector storing initial L2 error for all 1 <= N <= RB_size.
virtual Real get_stability_lower_bound()
Get a lower bound for the stability constant (e.g.
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...
virtual void legacy_read_offline_data_from_files(const std::string &directory_name="offline_data", bool read_error_bound_data=true, const bool read_binary_data=true)
Read in the saved Offline reduced basis data to initialize the system for Online solves.
virtual Real residual_scaling_numer(Real alpha_LB)
Specifies the residual scaling on the numerator to be used in the a posteriori error bound...
virtual unsigned int get_n_M_terms() const
Get Q_m, the number of terms in the affine expansion for the mass operator.
boostcopy::enable_if_c< ScalarTraits< T2 >::value, void >::type add(const T2 factor, const DenseMatrix< T3 > &mat)
Adds factor times mat to this matrix.
libmesh_assert(ctx)
virtual Number eval_F_theta(unsigned int q, const RBParameters &mu) const
Evaluate theta_q_f at the current parameter.
std::vector< std::vector< std::vector< Number > > > Fq_Mq_representor_innerprods
Vectors storing the residual representor inner products to be used in computing the residuals online...
std::vector< std::vector< Real > > RB_output_error_bounds_all_k
The error bounds for each RB output for all time-levels from the most recent rb_solve.
const RBParameters & get_parameters() const
Get the current parameters.
std::vector< Real > error_bound_all_k
The error bound data for all time-levels from the most recent rb_solve.
unsigned int get_time_step() const
Get/set the current time-step.
virtual void clear() override
Clear this TransientRBEvaluation object.
This class is part of the rbOOmit framework.
Definition: rb_parameters.h:52
virtual Real residual_scaling_denom(Real alpha_LB)
Specifies the residual scaling on the denominator to be used in the a posteriori error bound...
This class implements a C++ interface to the XDR (eXternal Data Representation) format.
Definition: xdr_cxx.h:67
std::vector< std::vector< std::vector< Number > > > Fq_Aq_representor_innerprods
Vectors storing the residual representor inner products to be used in computing the residuals online...
virtual Real rb_solve_again()
If a solve has already been performed, then we cached some data and we can perform a new solve much m...
std::vector< DenseVector< Number > > RB_initial_condition_all_N
The RB initial conditions (i.e.
This class is part of the rbOOmit framework.
Definition: rb_evaluation.h:50
virtual void clear_riesz_representors()
Clear all the Riesz representors that are used to compute the RB residual (and hence error bound)...
CompareTypes< T, T2 >::supertype dot(const DenseVector< T2 > &vec) const
Definition: dense_vector.h:492
std::vector< DenseMatrix< Number > > RB_Aq_vector
Dense matrices for the RB computations.
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)
Solve the system Ax=b given the input vector b.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
unsigned int get_n_output_terms(unsigned int output_index) const
Get the number of affine terms associated with the specified output.
Real eval_output_dual_norm(unsigned int n, const RBParameters &mu)
Evaluate the dual norm of output n for the current parameters.
static void assert_file_exists(const std::string &file_name)
Helper function that checks if file_name exists.
OStreamProxy out
virtual unsigned int get_n_basis_functions() const
Get the current number of basis functions.
virtual void legacy_read_offline_data_from_files(const std::string &directory_name="offline_data", bool read_error_bound_data=true, const bool read_binary_data=true) override
Read in the saved Offline reduced basis data to initialize the system for Online solves.
std::vector< DenseVector< Number > > RB_temporal_solution_data
Array storing the solution data at each time level from the most recent solve.
virtual void clear() override
Clear this RBEvaluation object.
Definition: rb_evaluation.C:59
static const bool value
Definition: xdr_io.C:54
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Definition: dense_matrix.h:895
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
void set_euler_theta(const Real euler_theta_in)
std::vector< std::vector< Number > > RB_outputs_all_k
The RB outputs for all time-levels from the most recent rb_solve.
virtual unsigned int size() const override final
Definition: dense_vector.h:104
unsigned int get_n_time_steps() const
Get/set the total number of time-steps.
std::vector< std::vector< std::vector< std::vector< Number > > > > Aq_Mq_representor_innerprods
void set_n_time_steps(const unsigned int K)
processor_id_type processor_id() const
TransientRBEvaluation(const Parallel::Communicator &comm_in)
Constructor.
Real get_control(const unsigned int k) const
Get/set the RHS control.
virtual Real rb_solve(unsigned int N) override
Perform online solve with the N RB basis functions, for the set of parameters in current_params, where 0 <= N <= RB_size.
RBThetaExpansion & get_rb_theta_expansion()
Get a reference to the rb_theta_expansion.
Definition: rb_evaluation.C:85
DenseMatrix< Number > RB_L2_matrix
Dense RB L2 matrix.
void vector_mult(DenseVector< T > &dest, const DenseVector< T > &arg) const
Performs the matrix-vector multiplication, dest := (*this) * arg.
std::vector< std::vector< std::vector< Number > > > Aq_Aq_representor_innerprods
std::vector< std::vector< DenseVector< Number > > > RB_output_vectors
The vectors storing the RB output vectors.