Line data Source code
1 : // rbOOmit: An implementation of the Certified Reduced Basis method.
2 : // Copyright (C) 2009, 2010 David J. Knezevic
3 :
4 : // This file is part of rbOOmit.
5 :
6 : // rbOOmit is free software; you can redistribute it and/or
7 : // modify it under the terms of the GNU Lesser General Public
8 : // License as published by the Free Software Foundation; either
9 : // version 2.1 of the License, or (at your option) any later version.
10 :
11 : // rbOOmit is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : // Lesser General Public License for more details.
15 :
16 : // You should have received a copy of the GNU Lesser General Public
17 : // License along with this library; if not, write to the Free Software
18 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 :
20 : // 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 :
39 140 : TransientRBEvaluation::TransientRBEvaluation(const Parallel::Communicator & comm_in) :
40 : RBEvaluation(comm_in),
41 156 : _rb_solve_data_cached(false)
42 : {
43 : // Indicate that we need to compute the RB
44 : // inner product matrix in this case
45 140 : compute_RB_inner_product = true;
46 140 : }
47 :
48 924 : TransientRBEvaluation::~TransientRBEvaluation () = default;
49 :
50 0 : void TransientRBEvaluation::clear()
51 : {
52 0 : Parent::clear();
53 :
54 0 : clear_riesz_representors();
55 0 : }
56 :
57 140 : void TransientRBEvaluation::clear_riesz_representors()
58 : {
59 140 : Parent::clear_riesz_representors();
60 :
61 : // Delete the M_q representors
62 136 : M_q_representor.clear();
63 140 : }
64 :
65 140 : void TransientRBEvaluation::resize_data_structures(const unsigned int Nmax,
66 : bool resize_error_bound_data)
67 : {
68 8 : LOG_SCOPE("resize_data_structures()", "TransientRBEvaluation");
69 :
70 140 : Parent::resize_data_structures(Nmax, resize_error_bound_data);
71 :
72 136 : RB_L2_matrix.resize(Nmax,Nmax);
73 136 : RB_LHS_matrix.resize(Nmax,Nmax);
74 136 : RB_RHS_matrix.resize(Nmax,Nmax);
75 136 : RB_RHS_save.resize(Nmax);
76 :
77 : TransientRBThetaExpansion & trans_theta_expansion =
78 140 : cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
79 140 : const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
80 140 : const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
81 140 : const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
82 :
83 : // Allocate dense matrices for RB solves
84 140 : RB_M_q_vector.resize(Q_m);
85 280 : for (unsigned int q=0; q<Q_m; q++)
86 : {
87 : // Initialize the memory for the RB matrices
88 140 : RB_M_q_vector[q].resize(Nmax,Nmax);
89 : }
90 :
91 : // Initialize the initial condition storage
92 140 : RB_initial_condition_all_N.resize(Nmax);
93 2940 : 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 2880 : RB_initial_condition_all_N[i].resize(i+1);
97 : }
98 :
99 140 : initial_L2_error_all_N.resize(Nmax, 0.);
100 :
101 :
102 140 : if (resize_error_bound_data)
103 : {
104 : // Initialize vectors for the norms of the representors
105 140 : Fq_Mq_representor_innerprods.resize(Q_f);
106 280 : for (unsigned int i=0; i<Q_f; i++)
107 : {
108 144 : Fq_Mq_representor_innerprods[i].resize(Q_m);
109 280 : for (unsigned int j=0; j<Q_m; j++)
110 : {
111 148 : Fq_Mq_representor_innerprods[i][j].resize(Nmax, 0.);
112 : }
113 : }
114 :
115 140 : unsigned int Q_m_hat = Q_m*(Q_m+1)/2;
116 140 : Mq_Mq_representor_innerprods.resize(Q_m_hat);
117 280 : for (unsigned int i=0; i<Q_m_hat; i++)
118 : {
119 144 : Mq_Mq_representor_innerprods[i].resize(Nmax);
120 2940 : for (unsigned int j=0; j<Nmax; j++)
121 : {
122 2960 : Mq_Mq_representor_innerprods[i][j].resize(Nmax, 0.);
123 : }
124 : }
125 :
126 140 : Aq_Mq_representor_innerprods.resize(Q_a);
127 560 : for (unsigned int i=0; i<Q_a; i++)
128 : {
129 432 : Aq_Mq_representor_innerprods[i].resize(Q_m);
130 840 : for (unsigned int j=0; j<Q_m; j++)
131 : {
132 444 : Aq_Mq_representor_innerprods[i][j].resize(Nmax);
133 8820 : for (unsigned int k=0; k<Nmax; k++)
134 : {
135 9120 : 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 140 : M_q_representor.resize(Q_m);
144 280 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
145 : {
146 144 : M_q_representor[q_m].resize(Nmax);
147 : }
148 : }
149 140 : }
150 :
151 22070 : Real TransientRBEvaluation::rb_solve(unsigned int N)
152 : {
153 4004 : LOG_SCOPE("rb_solve()", "TransientRBEvaluation");
154 :
155 22070 : 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 22070 : const RBParameters & mu = get_parameters();
159 :
160 : TransientRBThetaExpansion & trans_theta_expansion =
161 22070 : cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
162 22070 : const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
163 22070 : const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
164 22070 : const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
165 :
166 22070 : const unsigned int n_time_steps = get_n_time_steps();
167 22070 : const Real dt = get_delta_t();
168 22070 : const Real euler_theta = get_euler_theta();
169 :
170 : // Resize the RB and error bound vectors
171 22070 : error_bound_all_k.resize(n_time_steps+1);
172 22070 : RB_outputs_all_k.resize(trans_theta_expansion.get_n_outputs());
173 22070 : RB_output_error_bounds_all_k.resize(trans_theta_expansion.get_n_outputs());
174 110350 : for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
175 : {
176 96288 : RB_outputs_all_k[n].resize(n_time_steps+1, 0.);
177 96288 : RB_output_error_bounds_all_k[n].resize(n_time_steps+1, 0.);
178 : }
179 :
180 : // First assemble the mass matrix
181 26074 : DenseMatrix<Number> RB_mass_matrix_N(N,N);
182 2002 : RB_mass_matrix_N.zero();
183 26074 : DenseMatrix<Number> RB_M_q_m;
184 44140 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
185 : {
186 24072 : RB_M_q_vector[q_m].get_principal_submatrix(N, RB_M_q_m);
187 22070 : RB_mass_matrix_N.add(trans_theta_expansion.eval_M_theta(q_m, mu), RB_M_q_m);
188 : }
189 :
190 22070 : RB_LHS_matrix.resize(N,N);
191 2002 : RB_LHS_matrix.zero();
192 :
193 22070 : RB_RHS_matrix.resize(N,N);
194 2002 : RB_RHS_matrix.zero();
195 :
196 22070 : RB_LHS_matrix.add(1./dt, RB_mass_matrix_N);
197 22070 : RB_RHS_matrix.add(1./dt, RB_mass_matrix_N);
198 :
199 26074 : DenseMatrix<Number> RB_Aq_a;
200 88280 : for (unsigned int q_a=0; q_a<Q_a; q_a++)
201 : {
202 72216 : RB_Aq_vector[q_a].get_principal_submatrix(N, RB_Aq_a);
203 :
204 66210 : RB_LHS_matrix.add( euler_theta*trans_theta_expansion.eval_A_theta(q_a,mu), RB_Aq_a);
205 66210 : 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 22070 : DenseVector<Number> RB_Fq_f;
210 20068 : RB_RHS_save.resize(N);
211 2002 : RB_RHS_save.zero();
212 44140 : for (unsigned int q_f=0; q_f<Q_f; q_f++)
213 : {
214 24072 : RB_Fq_vector[q_f].get_principal_subvector(N, RB_Fq_f);
215 22070 : 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 22070 : set_time_step(0);
220 :
221 : // Resize/clear the solution vector
222 20068 : RB_solution.resize(N);
223 :
224 : // Load the initial condition into RB_solution
225 22070 : if (N > 0)
226 : {
227 20970 : RB_solution = RB_initial_condition_all_N[N-1];
228 : }
229 :
230 : // Resize/clear the old solution vector
231 20068 : old_RB_solution.resize(N);
232 :
233 : // Initialize the RB rhs
234 22070 : DenseVector<Number> RB_rhs(N);
235 2002 : RB_rhs.zero();
236 :
237 : // Initialize the vectors storing solution data
238 22070 : RB_temporal_solution_data.resize(n_time_steps+1);
239 2251140 : for (unsigned int time_level=0; time_level<=n_time_steps; time_level++)
240 : {
241 2229070 : RB_temporal_solution_data[time_level].resize(N);
242 : }
243 : // and load the initial data
244 4004 : RB_temporal_solution_data[0] = RB_solution;
245 :
246 : // Set outputs at initial time
247 : {
248 22070 : DenseVector<Number> RB_output_vector_N;
249 110350 : for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
250 : {
251 96288 : RB_outputs_all_k[n][0] = 0.;
252 176560 : for (unsigned int q_l=0; q_l<trans_theta_expansion.get_n_output_terms(n); q_l++)
253 : {
254 104296 : RB_output_vectors[n][q_l].get_principal_subvector(N, RB_output_vector_N);
255 88280 : 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 2002 : Real error_bound_sum = 0.;
262 2002 : Real alpha_LB = 0.;
263 22070 : if (evaluate_RB_error_bound)
264 : {
265 22070 : if (N > 0)
266 : {
267 22872 : error_bound_sum += pow( initial_L2_error_all_N[N-1], 2.);
268 : }
269 :
270 : // Set error bound at the initial time
271 22070 : 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 22070 : DenseVector<Number> RB_output_vector_N;
275 110350 : for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
276 : {
277 96288 : RB_outputs_all_k[n][0] = 0.;
278 176560 : for (unsigned int q_l=0; q_l<trans_theta_expansion.get_n_output_terms(n); q_l++)
279 : {
280 104296 : RB_output_vectors[n][q_l].get_principal_subvector(N, RB_output_vector_N);
281 88280 : 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 :
284 88280 : RB_output_error_bounds_all_k[n][0] = error_bound_all_k[0] * eval_output_dual_norm(n, nullptr);
285 : }
286 :
287 22070 : alpha_LB = get_stability_lower_bound();
288 :
289 : // Precompute time-invariant parts of the dual norm of the residual.
290 22070 : cache_online_residual_terms(N);
291 : }
292 :
293 2229070 : for (unsigned int time_level=1; time_level<=n_time_steps; time_level++)
294 : {
295 2207000 : set_time_step(time_level);
296 200200 : old_RB_solution = RB_solution;
297 :
298 : // Compute RB_rhs, as RB_LHS_matrix x old_RB_solution
299 2207000 : RB_RHS_matrix.vector_mult(RB_rhs, old_RB_solution);
300 :
301 : // Add forcing terms
302 2207000 : RB_rhs.add(get_control(time_level), RB_RHS_save);
303 :
304 2207000 : if (N > 0)
305 : {
306 2097000 : RB_LHS_matrix.lu_solve(RB_rhs, RB_solution);
307 : }
308 :
309 : // Save RB_solution for current time level
310 2207000 : RB_temporal_solution_data[time_level] = RB_solution;
311 :
312 : // Evaluate outputs
313 2207000 : DenseVector<Number> RB_output_vector_N;
314 11035000 : for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
315 : {
316 10429600 : RB_outputs_all_k[n][time_level] = 0.;
317 17656000 : for (unsigned int q_l=0; q_l<trans_theta_expansion.get_n_output_terms(n); q_l++)
318 : {
319 10429600 : RB_output_vectors[n][q_l].get_principal_subvector(N, RB_output_vector_N);
320 19257600 : RB_outputs_all_k[n][time_level] += trans_theta_expansion.eval_output_theta(n,q_l,mu)*
321 8828000 : RB_output_vector_N.dot(RB_solution);
322 : }
323 : }
324 :
325 : // Calculate RB error bounds
326 2207000 : if (evaluate_RB_error_bound)
327 : {
328 : // Evaluate the dual norm of the residual for RB_solution_vector
329 : // Real epsilon_N = uncached_compute_residual_dual_norm(N);
330 2207000 : Real epsilon_N = compute_residual_dual_norm(N);
331 :
332 2207000 : error_bound_sum += residual_scaling_numer(alpha_LB) * pow(epsilon_N, 2.);
333 :
334 : // store error bound at time-level _k
335 2207000 : error_bound_all_k[time_level] = std::sqrt(error_bound_sum/residual_scaling_denom(alpha_LB));
336 :
337 : // Now evaluated output error bounds
338 11035000 : for (unsigned int n=0; n<trans_theta_expansion.get_n_outputs(); n++)
339 : {
340 9628800 : RB_output_error_bounds_all_k[n][time_level] = error_bound_all_k[time_level] *
341 8828000 : eval_output_dual_norm(n, nullptr);
342 : }
343 : }
344 : }
345 :
346 22070 : _rb_solve_data_cached = true ;
347 :
348 22070 : if (evaluate_RB_error_bound) // Calculate the error bounds
349 : {
350 24072 : 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 0 : return -1.;
356 : }
357 18066 : }
358 :
359 0 : Real TransientRBEvaluation::rb_solve_again()
360 : {
361 0 : libmesh_assert(_rb_solve_data_cached);
362 :
363 0 : const unsigned int n_time_steps = get_n_time_steps();
364 : // Set system time level to 0
365 0 : set_time_step(0);
366 :
367 : // Resize/clear the solution vector
368 0 : const unsigned int N = RB_RHS_save.size();
369 0 : RB_solution.resize(N);
370 :
371 : // Load the initial condition into RB_solution
372 0 : if (N > 0)
373 0 : RB_solution = RB_initial_condition_all_N[N-1];
374 :
375 : // Resize/clear the old solution vector
376 0 : old_RB_solution.resize(N);
377 :
378 : // Initialize the RB rhs
379 0 : DenseVector<Number> RB_rhs(N);
380 0 : RB_rhs.zero();
381 :
382 0 : for (unsigned int time_level=1; time_level<=n_time_steps; time_level++)
383 : {
384 0 : set_time_step(time_level);
385 0 : old_RB_solution = RB_solution;
386 :
387 : // Compute RB_rhs, as *RB_lhs_matrix x old_RB_solution
388 0 : RB_RHS_matrix.vector_mult(RB_rhs, old_RB_solution);
389 :
390 : // Add forcing terms
391 0 : RB_rhs.add(get_control(time_level), RB_RHS_save);
392 :
393 0 : if (N > 0)
394 0 : RB_LHS_matrix.lu_solve(RB_rhs, RB_solution);
395 : }
396 :
397 : {
398 : // Just return -1. We did not compute the error bound
399 0 : return -1.;
400 : }
401 : }
402 :
403 0 : Real TransientRBEvaluation::get_error_bound_normalization()
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 0 : return 1.;
410 : }
411 :
412 2207000 : Real TransientRBEvaluation::residual_scaling_numer(Real)
413 : {
414 2207000 : return get_delta_t();
415 : }
416 :
417 22070 : void TransientRBEvaluation::cache_online_residual_terms(const unsigned int N)
418 : {
419 4004 : LOG_SCOPE("cache_online_residual_terms()", "TransientRBEvaluation");
420 :
421 26074 : const RBParameters mu = get_parameters();
422 :
423 : TransientRBThetaExpansion & trans_theta_expansion =
424 22070 : cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
425 22070 : const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
426 22070 : const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
427 22070 : const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
428 :
429 22070 : cached_Fq_term = 0.;
430 2002 : unsigned int q=0;
431 44140 : for (unsigned int q_f1=0; q_f1<Q_f; q_f1++)
432 : {
433 22070 : Number cached_theta_q_f1 = trans_theta_expansion.eval_F_theta(q_f1,mu);
434 44140 : for (unsigned int q_f2=q_f1; q_f2<Q_f; q_f2++)
435 : {
436 22070 : Real delta = (q_f1==q_f2) ? 1. : 2.;
437 22070 : cached_Fq_term += delta*cached_theta_q_f1*trans_theta_expansion.eval_F_theta(q_f2,mu) *
438 22070 : Fq_representor_innerprods[q];
439 :
440 22070 : q++;
441 : }
442 : }
443 :
444 20068 : cached_Fq_Aq_vector.resize(N);
445 44140 : for (unsigned int q_f=0; q_f<Q_f; q_f++)
446 : {
447 22070 : Number cached_theta_q_f = trans_theta_expansion.eval_F_theta(q_f,mu);
448 88280 : for (unsigned int q_a=0; q_a<Q_a; q_a++)
449 : {
450 66210 : Number cached_theta_q_a = trans_theta_expansion.eval_A_theta(q_a,mu);
451 697410 : for (unsigned int i=0; i<N; i++)
452 : {
453 688320 : cached_Fq_Aq_vector(i) += 2.*cached_theta_q_f*cached_theta_q_a*
454 745440 : Fq_Aq_representor_innerprods[q_f][q_a][i];
455 : }
456 : }
457 : }
458 :
459 20068 : cached_Aq_Aq_matrix.resize(N,N);
460 2002 : q=0;
461 88280 : for (unsigned int q_a1=0; q_a1<Q_a; q_a1++)
462 : {
463 66210 : Number cached_theta_q_a1 = trans_theta_expansion.eval_A_theta(q_a1,mu);
464 198630 : for (unsigned int q_a2=q_a1; q_a2<Q_a; q_a2++)
465 : {
466 132420 : Number cached_theta_q_a2 = trans_theta_expansion.eval_A_theta(q_a2,mu);
467 132420 : Real delta = (q_a1==q_a2) ? 1. : 2.;
468 :
469 1394820 : for (unsigned int i=0; i<N; i++)
470 : {
471 17732400 : for (unsigned int j=0; j<N; j++)
472 : {
473 16470000 : cached_Aq_Aq_matrix(i,j) += delta*
474 16470000 : cached_theta_q_a1*cached_theta_q_a2*
475 19443600 : Aq_Aq_representor_innerprods[q][i][j];
476 : }
477 : }
478 132420 : q++;
479 : }
480 : }
481 :
482 20068 : cached_Fq_Mq_vector.resize(N);
483 44140 : for (unsigned int q_f=0; q_f<Q_f; q_f++)
484 : {
485 22070 : Number cached_theta_q_f = trans_theta_expansion.eval_F_theta(q_f,mu);
486 44140 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
487 : {
488 22070 : Number cached_theta_q_m = trans_theta_expansion.eval_M_theta(q_m,mu);
489 232470 : for (unsigned int i=0; i<N; i++)
490 : {
491 286560 : 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 :
496 20068 : cached_Aq_Mq_matrix.resize(N,N);
497 88280 : for (unsigned int q_a=0; q_a<Q_a; q_a++)
498 : {
499 66210 : Number cached_theta_q_a = trans_theta_expansion.eval_A_theta(q_a,mu);
500 :
501 132420 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
502 : {
503 66210 : Number cached_theta_q_m = trans_theta_expansion.eval_M_theta(q_m,mu);
504 :
505 697410 : for (unsigned int i=0; i<N; i++)
506 : {
507 8866200 : for (unsigned int j=0; j<N; j++)
508 : {
509 11952000 : 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 :
515 20068 : cached_Mq_Mq_matrix.resize(N,N);
516 2002 : q=0;
517 44140 : for (unsigned int q_m1=0; q_m1<Q_m; q_m1++)
518 : {
519 22070 : Number cached_theta_q_m1 = trans_theta_expansion.eval_M_theta(q_m1,mu);
520 44140 : for (unsigned int q_m2=q_m1; q_m2<Q_m; q_m2++)
521 : {
522 22070 : Number cached_theta_q_m2 = trans_theta_expansion.eval_M_theta(q_m2,mu);
523 22070 : Real delta = (q_m1==q_m2) ? 1. : 2.;
524 :
525 232470 : for (unsigned int i=0; i<N; i++)
526 : {
527 2955400 : for (unsigned int j=0; j<N; j++)
528 : {
529 2745000 : cached_Mq_Mq_matrix(i,j) += delta*
530 2745000 : cached_theta_q_m1*cached_theta_q_m2*
531 3240600 : Mq_Mq_representor_innerprods[q][i][j];
532 : }
533 : }
534 22070 : q++;
535 : }
536 : }
537 22070 : }
538 :
539 2207000 : Real TransientRBEvaluation::compute_residual_dual_norm(const unsigned int N)
540 : {
541 400400 : 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 2207000 : const Real dt = get_delta_t();
547 2207000 : const Real euler_theta = get_euler_theta();
548 2207000 : const Real current_control = get_control(get_time_step());
549 :
550 2207000 : DenseVector<Number> RB_u_euler_theta(N);
551 2207000 : DenseVector<Number> mass_coeffs(N);
552 23247000 : for (unsigned int i=0; i<N; i++)
553 : {
554 24848000 : RB_u_euler_theta(i) = euler_theta*RB_solution(i) +
555 22944000 : (1.-euler_theta)*old_RB_solution(i);
556 22944000 : mass_coeffs(i) = -(RB_solution(i) - old_RB_solution(i))/dt;
557 : }
558 :
559 2207000 : Number residual_norm_sq = current_control*current_control*cached_Fq_term;
560 :
561 2207000 : residual_norm_sq += current_control*RB_u_euler_theta.dot(cached_Fq_Aq_vector);
562 2207000 : residual_norm_sq += current_control*mass_coeffs.dot(cached_Fq_Mq_vector);
563 :
564 23247000 : for (unsigned int i=0; i<N; i++)
565 295540000 : for (unsigned int j=0; j<N; j++)
566 : {
567 324060000 : residual_norm_sq += RB_u_euler_theta(i)*RB_u_euler_theta(j)*cached_Aq_Aq_matrix(i,j);
568 299280000 : residual_norm_sq += mass_coeffs(i)*mass_coeffs(j)*cached_Mq_Mq_matrix(i,j);
569 299280000 : residual_norm_sq += RB_u_euler_theta(i)*mass_coeffs(j)*cached_Aq_Mq_matrix(i,j);
570 : }
571 :
572 :
573 2207000 : if (libmesh_real(residual_norm_sq) < 0)
574 : {
575 0 : libMesh::out << "Warning: Square of residual norm is negative "
576 0 : << "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 0 : residual_norm_sq = std::abs(residual_norm_sq);
582 : }
583 :
584 4414000 : return libmesh_real(std::sqrt( residual_norm_sq ));
585 : }
586 :
587 0 : Real TransientRBEvaluation::uncached_compute_residual_dual_norm(const unsigned int N)
588 : {
589 0 : 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 0 : const RBParameters & mu = get_parameters();
595 :
596 : TransientRBThetaExpansion & trans_theta_expansion =
597 0 : cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
598 0 : const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
599 0 : const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
600 0 : const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
601 :
602 0 : const Real dt = get_delta_t();
603 0 : const Real euler_theta = get_euler_theta();
604 :
605 0 : std::vector<Number> RB_u_euler_theta(N);
606 0 : std::vector<Number> mass_coeffs(N);
607 0 : for (unsigned int i=0; i<N; i++)
608 : {
609 0 : RB_u_euler_theta[i] = euler_theta*RB_solution(i) +
610 0 : (1.-euler_theta)*old_RB_solution(i);
611 0 : mass_coeffs[i] = -(RB_solution(i) - old_RB_solution(i))/dt;
612 : }
613 :
614 0 : Number residual_norm_sq = 0.;
615 :
616 0 : unsigned int q=0;
617 0 : for (unsigned int q_f1=0; q_f1<Q_f; q_f1++)
618 : {
619 0 : Number cached_theta_q_f1 = trans_theta_expansion.eval_F_theta(q_f1,mu);
620 0 : for (unsigned int q_f2=q_f1; q_f2<Q_f; q_f2++)
621 : {
622 0 : Real delta = (q_f1==q_f2) ? 1. : 2.;
623 0 : residual_norm_sq += delta*cached_theta_q_f1*trans_theta_expansion.eval_F_theta(q_f2,mu) * Fq_representor_innerprods[q];
624 :
625 0 : q++;
626 : }
627 : }
628 :
629 0 : for (unsigned int q_f=0; q_f<Q_f; q_f++)
630 : {
631 0 : Number cached_theta_q_f = trans_theta_expansion.eval_F_theta(q_f,mu);
632 0 : for (unsigned int q_a=0; q_a<Q_a; q_a++)
633 : {
634 0 : Number cached_theta_q_a = trans_theta_expansion.eval_A_theta(q_a,mu);
635 0 : for (unsigned int i=0; i<N; i++)
636 : {
637 0 : residual_norm_sq += 2.*RB_u_euler_theta[i]*cached_theta_q_f*cached_theta_q_a*
638 0 : Fq_Aq_representor_innerprods[q_f][q_a][i];
639 : }
640 : }
641 : }
642 :
643 0 : q=0;
644 0 : for (unsigned int q_a1=0; q_a1<Q_a; q_a1++)
645 : {
646 0 : Number cached_theta_q_a1 = trans_theta_expansion.eval_A_theta(q_a1,mu);
647 0 : for (unsigned int q_a2=q_a1; q_a2<Q_a; q_a2++)
648 : {
649 0 : Number cached_theta_q_a2 = trans_theta_expansion.eval_A_theta(q_a2,mu);
650 0 : Real delta = (q_a1==q_a2) ? 1. : 2.;
651 :
652 0 : for (unsigned int i=0; i<N; i++)
653 : {
654 0 : for (unsigned int j=0; j<N; j++)
655 : {
656 0 : residual_norm_sq += delta*RB_u_euler_theta[i]*RB_u_euler_theta[j]*
657 0 : cached_theta_q_a1*cached_theta_q_a2*
658 0 : Aq_Aq_representor_innerprods[q][i][j];
659 : }
660 : }
661 0 : q++;
662 : }
663 : }
664 :
665 : // Now add the terms due to the time-derivative
666 0 : q=0;
667 0 : for (unsigned int q_m1=0; q_m1<Q_m; q_m1++)
668 : {
669 0 : Number cached_theta_q_m1 = trans_theta_expansion.eval_M_theta(q_m1,mu);
670 0 : for (unsigned int q_m2=q_m1; q_m2<Q_m; q_m2++)
671 : {
672 0 : Number cached_theta_q_m2 = trans_theta_expansion.eval_M_theta(q_m2,mu);
673 0 : Real delta = (q_m1==q_m2) ? 1. : 2.;
674 :
675 0 : for (unsigned int i=0; i<N; i++)
676 : {
677 0 : for (unsigned int j=0; j<N; j++)
678 : {
679 0 : residual_norm_sq += delta*mass_coeffs[i]*mass_coeffs[j]*
680 0 : cached_theta_q_m1*cached_theta_q_m2*
681 0 : Mq_Mq_representor_innerprods[q][i][j];
682 : }
683 : }
684 0 : q++;
685 : }
686 : }
687 :
688 0 : for (unsigned int q_f=0; q_f<Q_f; q_f++)
689 : {
690 0 : Number cached_theta_q_f = trans_theta_expansion.eval_F_theta(q_f,mu);
691 0 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
692 : {
693 0 : Number cached_theta_q_m = trans_theta_expansion.eval_M_theta(q_m,mu);
694 0 : for (unsigned int i=0; i<N; i++)
695 : {
696 0 : 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 0 : for (unsigned int q_a=0; q_a<Q_a; q_a++)
702 : {
703 0 : Number cached_theta_q_a = trans_theta_expansion.eval_A_theta(q_a,mu);
704 :
705 0 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
706 : {
707 0 : Number cached_theta_q_m = trans_theta_expansion.eval_M_theta(q_m,mu);
708 :
709 0 : for (unsigned int i=0; i<N; i++)
710 : {
711 0 : for (unsigned int j=0; j<N; j++)
712 : {
713 0 : residual_norm_sq += 2.*RB_u_euler_theta[i]*mass_coeffs[j]*
714 0 : cached_theta_q_a*cached_theta_q_m*
715 0 : Aq_Mq_representor_innerprods[q_a][q_m][i][j];
716 : }
717 : }
718 : }
719 : }
720 :
721 0 : if (libmesh_real(residual_norm_sq) < 0)
722 : {
723 0 : libMesh::out << "Warning: Square of residual norm is negative "
724 0 : << "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 0 : 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 0 : return libmesh_real(std::sqrt( residual_norm_sq ));
736 : }
737 :
738 70 : void TransientRBEvaluation::legacy_write_offline_data_to_files(const std::string & directory_name,
739 : const bool write_binary_data)
740 : {
741 4 : LOG_SCOPE("legacy_write_offline_data_to_files()", "TransientRBEvaluation");
742 :
743 70 : Parent::legacy_write_offline_data_to_files(directory_name);
744 :
745 : TransientRBThetaExpansion & trans_theta_expansion =
746 70 : cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
747 70 : const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
748 70 : const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
749 70 : const unsigned int Q_f = trans_theta_expansion.get_n_F_terms();
750 :
751 70 : const unsigned int n_bfs = get_n_basis_functions();
752 :
753 : // The writing mode: ENCODE for binary, WRITE for ASCII
754 70 : XdrMODE mode = write_binary_data ? ENCODE : WRITE;
755 :
756 : // The suffix to use for all the files that are written out
757 72 : const std::string suffix = write_binary_data ? ".xdr" : ".dat";
758 :
759 72 : if (this->processor_id() == 0)
760 : {
761 13 : std::ostringstream file_name;
762 :
763 : // Write out the temporal discretization data
764 21 : file_name.str("");
765 10 : file_name << directory_name << "/temporal_discretization_data" << suffix;
766 13 : Xdr temporal_discretization_data_out(file_name.str(), mode);
767 :
768 : Real real_value; unsigned int int_value;
769 11 : real_value = get_delta_t(); temporal_discretization_data_out << real_value;
770 11 : real_value = get_euler_theta(); temporal_discretization_data_out << real_value;
771 11 : int_value = get_n_time_steps(); temporal_discretization_data_out << int_value;
772 11 : int_value = get_time_step(); temporal_discretization_data_out << int_value;
773 11 : temporal_discretization_data_out.close();
774 :
775 :
776 : // Write out the L2 matrix
777 21 : file_name.str("");
778 10 : file_name << directory_name << "/RB_L2_matrix" << suffix;
779 14 : Xdr RB_L2_matrix_out(file_name.str(), mode);
780 :
781 231 : for (unsigned int i=0; i<n_bfs; i++)
782 : {
783 4620 : for (unsigned int j=0; j<n_bfs; j++)
784 : {
785 800 : RB_L2_matrix_out << RB_L2_matrix(i,j);
786 : }
787 : }
788 11 : RB_L2_matrix_out.close();
789 :
790 : // Write out the M_q matrices
791 22 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
792 : {
793 21 : file_name.str("");
794 11 : file_name << directory_name << "/RB_M_";
795 : file_name << std::setw(3)
796 : << std::setprecision(0)
797 1 : << std::setfill('0')
798 1 : << std::right
799 1 : << q_m;
800 1 : file_name << suffix;
801 14 : Xdr RB_M_q_m_out(file_name.str(), mode);
802 :
803 231 : for (unsigned int i=0; i<n_bfs; i++)
804 : {
805 4620 : for (unsigned int j=0; j<n_bfs; j++)
806 : {
807 1200 : RB_M_q_m_out << RB_M_q_vector[q_m](i,j);
808 : }
809 : }
810 11 : RB_M_q_m_out.close();
811 9 : }
812 :
813 : // Write out the initial condition data
814 : // and the initial L2 error for all N
815 21 : file_name.str("");
816 10 : file_name << directory_name << "/initial_conditions" << suffix;
817 13 : Xdr initial_conditions_out(file_name.str(), mode);
818 21 : file_name.str("");
819 10 : file_name << directory_name << "/initial_L2_error" << suffix;
820 14 : Xdr initial_L2_error_out(file_name.str(), mode);
821 :
822 231 : for (unsigned int i=0; i<n_bfs; i++)
823 : {
824 240 : initial_L2_error_out << initial_L2_error_all_N[i];
825 2530 : for (unsigned int j=0; j<=i; j++)
826 : {
827 630 : initial_conditions_out << RB_initial_condition_all_N[i](j);
828 : }
829 : }
830 11 : initial_conditions_out.close();
831 11 : initial_L2_error_out.close();
832 :
833 : // Next write out the Fq_Mq representor norm data
834 21 : file_name.str("");
835 10 : file_name << directory_name << "/Fq_Mq_terms" << suffix;
836 14 : Xdr RB_Fq_Mq_terms_out(file_name.str(), mode);
837 :
838 22 : for (unsigned int q_f=0; q_f<Q_f; q_f++)
839 : {
840 22 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
841 : {
842 231 : for (unsigned int i=0; i<n_bfs; i++)
843 : {
844 280 : RB_Fq_Mq_terms_out << Fq_Mq_representor_innerprods[q_f][q_m][i];
845 : }
846 : }
847 : }
848 11 : RB_Fq_Mq_terms_out.close();
849 :
850 : // Next write out the Mq_Mq representor norm data
851 21 : file_name.str("");
852 10 : file_name << directory_name << "/Mq_Mq_terms" << suffix;
853 13 : Xdr RB_Mq_Mq_terms_out(file_name.str(), mode);
854 :
855 11 : unsigned int Q_m_hat = Q_m*(Q_m+1)/2;
856 22 : for (unsigned int q=0; q<Q_m_hat; q++)
857 : {
858 231 : for (unsigned int i=0; i<n_bfs; i++)
859 : {
860 4620 : for (unsigned int j=0; j<n_bfs; j++)
861 : {
862 5600 : RB_Mq_Mq_terms_out << Mq_Mq_representor_innerprods[q][i][j];
863 : }
864 : }
865 : }
866 11 : RB_Mq_Mq_terms_out.close();
867 :
868 : // Next write out the Aq_Mq representor norm data
869 21 : file_name.str("");
870 10 : file_name << directory_name << "/Aq_Mq_terms" << suffix;
871 14 : Xdr RB_Aq_Mq_terms_out(file_name.str(), mode);
872 :
873 44 : for (unsigned int q_a=0; q_a<Q_a; q_a++)
874 : {
875 66 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
876 : {
877 693 : for (unsigned int i=0; i<n_bfs; i++)
878 : {
879 13860 : for (unsigned int j=0; j<n_bfs; j++)
880 : {
881 18000 : RB_Aq_Mq_terms_out << Aq_Mq_representor_innerprods[q_a][q_m][i][j];
882 : }
883 : }
884 : }
885 : }
886 11 : RB_Aq_Mq_terms_out.close();
887 9 : }
888 70 : }
889 :
890 70 : 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 4 : LOG_SCOPE("legacy_read_offline_data_from_files()", "TransientRBEvaluation");
895 :
896 70 : Parent::legacy_read_offline_data_from_files(directory_name);
897 :
898 : TransientRBThetaExpansion & trans_theta_expansion =
899 70 : cast_ref<TransientRBThetaExpansion &>(get_rb_theta_expansion());
900 70 : const unsigned int Q_m = trans_theta_expansion.get_n_M_terms();
901 70 : const unsigned int Q_a = trans_theta_expansion.get_n_A_terms();
902 70 : 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 70 : unsigned int n_bfs = this->get_n_basis_functions();
907 :
908 : // The reading mode: DECODE for binary, READ for ASCII
909 70 : XdrMODE mode = read_binary_data ? DECODE : READ;
910 :
911 : // The suffix to use for all the files that are written out
912 72 : const std::string suffix = read_binary_data ? ".xdr" : ".dat";
913 :
914 : // The string stream we'll use to make the file names
915 74 : std::ostringstream file_name;
916 :
917 : // Write out the temporal discretization data
918 138 : file_name.str("");
919 68 : file_name << directory_name << "/temporal_discretization_data" << suffix;
920 138 : assert_file_exists(file_name.str());
921 :
922 140 : Xdr temporal_discretization_data_in(file_name.str(), mode);
923 :
924 : Real real_value; unsigned int int_value;
925 70 : temporal_discretization_data_in >> real_value; set_delta_t(real_value);
926 70 : temporal_discretization_data_in >> real_value; set_euler_theta(real_value);
927 70 : temporal_discretization_data_in >> int_value; set_n_time_steps(int_value);
928 70 : temporal_discretization_data_in >> int_value; set_time_step(int_value);
929 70 : temporal_discretization_data_in.close();
930 :
931 138 : file_name.str("");
932 68 : file_name << directory_name << "/RB_L2_matrix" << suffix;
933 138 : assert_file_exists(file_name.str());
934 :
935 76 : Xdr RB_L2_matrix_in(file_name.str(), mode);
936 :
937 1470 : for (unsigned int i=0; i<n_bfs; i++)
938 : {
939 29400 : for (unsigned int j=0; j<n_bfs; j++)
940 : {
941 0 : Number value;
942 1600 : RB_L2_matrix_in >> value;
943 28800 : RB_L2_matrix(i,j) = value;
944 : }
945 : }
946 70 : RB_L2_matrix_in.close();
947 :
948 : // Read in the M_q matrices
949 140 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
950 : {
951 138 : file_name.str("");
952 70 : file_name << directory_name << "/RB_M_";
953 : file_name << std::setw(3)
954 : << std::setprecision(0)
955 2 : << std::setfill('0')
956 2 : << std::right
957 2 : << q_m;
958 :
959 2 : file_name << suffix;
960 138 : assert_file_exists(file_name.str());
961 :
962 76 : Xdr RB_M_q_m_in(file_name.str(), mode);
963 :
964 1470 : for (unsigned int i=0; i<n_bfs; i++)
965 : {
966 29400 : for (unsigned int j=0; j<n_bfs; j++)
967 : {
968 0 : Number value;
969 1600 : RB_M_q_m_in >> value;
970 28800 : RB_M_q_vector[q_m](i,j) = value;
971 : }
972 : }
973 70 : RB_M_q_m_in.close();
974 66 : }
975 :
976 :
977 : // Read in the initial condition data
978 : // and the initial L2 error for all N
979 138 : file_name.str("");
980 68 : file_name << directory_name << "/initial_conditions" << suffix;
981 138 : assert_file_exists(file_name.str());
982 :
983 74 : Xdr initial_conditions_in(file_name.str(), mode);
984 :
985 138 : file_name.str("");
986 68 : file_name << directory_name << "/initial_L2_error" << suffix;
987 138 : assert_file_exists(file_name.str());
988 :
989 76 : Xdr initial_L2_error_in(file_name.str(), mode);
990 :
991 1470 : for (unsigned int i=0; i<n_bfs; i++)
992 : {
993 1440 : initial_L2_error_in >> initial_L2_error_all_N[i];
994 16100 : for (unsigned int j=0; j<=i; j++)
995 : {
996 1260 : initial_conditions_in >> RB_initial_condition_all_N[i](j);
997 : }
998 : }
999 70 : initial_conditions_in.close();
1000 70 : initial_L2_error_in.close();
1001 :
1002 :
1003 70 : if (read_error_bound_data)
1004 : {
1005 : // Next read in the Fq_Mq representor norm data
1006 138 : file_name.str("");
1007 68 : file_name << directory_name << "/Fq_Mq_terms" << suffix;
1008 138 : assert_file_exists(file_name.str());
1009 :
1010 76 : Xdr RB_Fq_Mq_terms_in(file_name.str(), mode);
1011 :
1012 140 : for (unsigned int q_f=0; q_f<Q_f; q_f++)
1013 : {
1014 140 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
1015 : {
1016 1470 : for (unsigned int i=0; i<n_bfs; i++)
1017 : {
1018 1520 : RB_Fq_Mq_terms_in >> Fq_Mq_representor_innerprods[q_f][q_m][i];
1019 : }
1020 : }
1021 : }
1022 70 : RB_Fq_Mq_terms_in.close();
1023 :
1024 : // Next read in the Mq_Mq representor norm data
1025 138 : file_name.str("");
1026 68 : file_name << directory_name << "/Mq_Mq_terms" << suffix;
1027 138 : assert_file_exists(file_name.str());
1028 :
1029 74 : Xdr RB_Mq_Mq_terms_in(file_name.str(), mode);
1030 :
1031 70 : unsigned int Q_m_hat = Q_m*(Q_m+1)/2;
1032 140 : for (unsigned int q=0; q<Q_m_hat; q++)
1033 : {
1034 1470 : for (unsigned int i=0; i<n_bfs; i++)
1035 : {
1036 29400 : for (unsigned int j=0; j<n_bfs; j++)
1037 : {
1038 30400 : RB_Mq_Mq_terms_in >> Mq_Mq_representor_innerprods[q][i][j];
1039 : }
1040 : }
1041 : }
1042 70 : RB_Mq_Mq_terms_in.close();
1043 :
1044 : // Next read in the Aq_Mq representor norm data
1045 138 : file_name.str("");
1046 68 : file_name << directory_name << "/Aq_Mq_terms" << suffix;
1047 138 : assert_file_exists(file_name.str());
1048 :
1049 76 : Xdr RB_Aq_Mq_terms_in(file_name.str(), mode);
1050 :
1051 280 : for (unsigned int q_a=0; q_a<Q_a; q_a++)
1052 : {
1053 420 : for (unsigned int q_m=0; q_m<Q_m; q_m++)
1054 : {
1055 4410 : for (unsigned int i=0; i<n_bfs; i++)
1056 : {
1057 88200 : for (unsigned int j=0; j<n_bfs; j++)
1058 : {
1059 93600 : RB_Aq_Mq_terms_in >> Aq_Mq_representor_innerprods[q_a][q_m][i][j];
1060 : }
1061 : }
1062 : }
1063 : }
1064 70 : RB_Aq_Mq_terms_in.close();
1065 66 : }
1066 136 : }
1067 :
1068 : }
|