LCOV - code coverage report
Current view: top level - src/reduced_basis - rb_evaluation.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 520 552 94.2 %
Date: 2025-08-19 19:27:09 Functions: 36 42 85.7 %
Legend: Lines: hit not hit

          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/rb_evaluation.h"
      22             : #include "libmesh/rb_theta_expansion.h"
      23             : 
      24             : // libMesh includes
      25             : #include "libmesh/libmesh_common.h"
      26             : #include "libmesh/libmesh_version.h"
      27             : #include "libmesh/system.h"
      28             : #include "libmesh/numeric_vector.h"
      29             : #include "libmesh/libmesh_logging.h"
      30             : #include "libmesh/xdr_cxx.h"
      31             : #include "libmesh/mesh_tools.h"
      32             : #include "libmesh/utility.h"
      33             : 
      34             : // TIMPI includes
      35             : #include "timpi/communicator.h"
      36             : 
      37             : // C/C++ includes
      38             : #include <sys/types.h>
      39             : #include <sys/stat.h>
      40             : #include <errno.h>
      41             : #include <fstream>
      42             : #include <sstream>
      43             : #include <iomanip>
      44             : 
      45             : namespace libMesh
      46             : {
      47             : 
      48         568 : RBEvaluation::RBEvaluation (const Parallel::Communicator & comm_in)
      49             :   :
      50             :   ParallelObject(comm_in),
      51         536 :   evaluate_RB_error_bound(true),
      52         536 :   compute_RB_inner_product(false),
      53         568 :   rb_theta_expansion(nullptr)
      54             : {
      55         568 : }
      56             : 
      57        1608 : RBEvaluation::~RBEvaluation() = default;
      58             : 
      59           0 : void RBEvaluation::clear()
      60             : {
      61           0 :   LOG_SCOPE("clear()", "RBEvaluation");
      62             : 
      63             :   // Clear the basis functions
      64           0 :   basis_functions.clear();
      65           0 :   set_n_basis_functions(0);
      66             : 
      67           0 :   clear_riesz_representors();
      68             : 
      69             :   // Clear the Greedy param list
      70           0 :   for (auto & plist : greedy_param_list)
      71           0 :     plist.clear();
      72           0 :   greedy_param_list.clear();
      73           0 : }
      74             : 
      75         284 : void RBEvaluation::set_n_basis_functions(unsigned int n_bfs)
      76             : {
      77         284 :   basis_functions.resize(n_bfs);
      78         284 : }
      79             : 
      80         568 : void RBEvaluation::set_rb_theta_expansion(RBThetaExpansion & rb_theta_expansion_in)
      81             : {
      82         568 :   rb_theta_expansion = &rb_theta_expansion_in;
      83         568 : }
      84             : 
      85     6156325 : RBThetaExpansion & RBEvaluation::get_rb_theta_expansion()
      86             : {
      87     6156325 :   libmesh_error_msg_if(!is_rb_theta_expansion_initialized(),
      88             :                        "Error: rb_theta_expansion hasn't been initialized yet");
      89             : 
      90     6156325 :   return *rb_theta_expansion;
      91             : }
      92             : 
      93        2342 : const RBThetaExpansion & RBEvaluation::get_rb_theta_expansion() const
      94             : {
      95        2342 :   libmesh_error_msg_if(!is_rb_theta_expansion_initialized(),
      96             :                        "Error: rb_theta_expansion hasn't been initialized yet");
      97             : 
      98        2342 :   return *rb_theta_expansion;
      99             : }
     100             : 
     101     6158667 : bool RBEvaluation::is_rb_theta_expansion_initialized() const
     102             : {
     103     6158667 :   if (rb_theta_expansion)
     104             :     {
     105      178454 :       return true;
     106             :     }
     107             :   else
     108             :     {
     109           0 :       return false;
     110             :     }
     111             : }
     112             : 
     113         568 : void RBEvaluation::resize_data_structures(const unsigned int Nmax,
     114             :                                           bool resize_error_bound_data)
     115             : {
     116          32 :   LOG_SCOPE("resize_data_structures()", "RBEvaluation");
     117             : 
     118         568 :   libmesh_error_msg_if(Nmax < this->get_n_basis_functions(),
     119             :                        "Error: Cannot set Nmax to be less than the current number of basis functions.");
     120             : 
     121             :   // Resize/clear inner product matrix
     122         568 :   if (compute_RB_inner_product)
     123         136 :     RB_inner_product_matrix.resize(Nmax,Nmax);
     124             : 
     125             :   // Allocate dense matrices for RB solves
     126         568 :   RB_Aq_vector.resize(rb_theta_expansion->get_n_A_terms());
     127             : 
     128        2272 :   for (unsigned int q=0; q<rb_theta_expansion->get_n_A_terms(); q++)
     129             :     {
     130             :       // Initialize the memory for the RB matrices
     131        1704 :       RB_Aq_vector[q].resize(Nmax,Nmax);
     132             :     }
     133             : 
     134         568 :   RB_Fq_vector.resize(rb_theta_expansion->get_n_F_terms());
     135             : 
     136        2556 :   for (unsigned int q=0; q<rb_theta_expansion->get_n_F_terms(); q++)
     137             :     {
     138             :       // Initialize the memory for the RB vectors
     139        1988 :       RB_Fq_vector[q].resize(Nmax);
     140             :     }
     141             : 
     142             : 
     143             :   // Initialize the RB output vectors
     144         568 :   RB_output_vectors.resize(rb_theta_expansion->get_n_outputs());
     145        1704 :   for (unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++)
     146             :     {
     147        1168 :       RB_output_vectors[n].resize(rb_theta_expansion->get_n_output_terms(n));
     148        2272 :       for (unsigned int q_l=0; q_l<rb_theta_expansion->get_n_output_terms(n); q_l++)
     149             :         {
     150        1168 :           RB_output_vectors[n][q_l].resize(Nmax);
     151             :         }
     152             :     }
     153             : 
     154             :   // Initialize vectors storing output data
     155         568 :   RB_outputs.resize(rb_theta_expansion->get_n_outputs(), 0.);
     156             : 
     157             : 
     158         568 :   if (resize_error_bound_data)
     159             :     {
     160             :       // Initialize vectors for the norms of the Fq representors
     161         568 :       unsigned int Q_f_hat = rb_theta_expansion->get_n_F_terms()*(rb_theta_expansion->get_n_F_terms()+1)/2;
     162         568 :       Fq_representor_innerprods.resize(Q_f_hat);
     163             : 
     164             :       // Initialize vectors for the norms of the representors
     165         568 :       Fq_Aq_representor_innerprods.resize(rb_theta_expansion->get_n_F_terms());
     166        2556 :       for (unsigned int i=0; i<rb_theta_expansion->get_n_F_terms(); i++)
     167             :         {
     168        2044 :           Fq_Aq_representor_innerprods[i].resize(rb_theta_expansion->get_n_A_terms());
     169        7952 :           for (unsigned int j=0; j<rb_theta_expansion->get_n_A_terms(); j++)
     170             :             {
     171        6300 :               Fq_Aq_representor_innerprods[i][j].resize(Nmax, 0.);
     172             :             }
     173             :         }
     174             : 
     175         568 :       unsigned int Q_a_hat = rb_theta_expansion->get_n_A_terms()*(rb_theta_expansion->get_n_A_terms()+1)/2;
     176         568 :       Aq_Aq_representor_innerprods.resize(Q_a_hat);
     177        3976 :       for (unsigned int i=0; i<Q_a_hat; i++)
     178             :         {
     179        3504 :           Aq_Aq_representor_innerprods[i].resize(Nmax);
     180       62904 :           for (unsigned int j=0; j<Nmax; j++)
     181             :             {
     182       62856 :               Aq_Aq_representor_innerprods[i][j].resize(Nmax, 0.);
     183             :             }
     184             :         }
     185             : 
     186         568 :       RB_output_error_bounds.resize(rb_theta_expansion->get_n_outputs(), 0.);
     187             : 
     188             :       // Resize the output dual norm vectors
     189         568 :       output_dual_innerprods.resize(rb_theta_expansion->get_n_outputs());
     190        1704 :       for (unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++)
     191             :         {
     192        1136 :           unsigned int Q_l_hat = rb_theta_expansion->get_n_output_terms(n)*(rb_theta_expansion->get_n_output_terms(n)+1)/2;
     193        1168 :           output_dual_innerprods[n].resize(Q_l_hat);
     194             :         }
     195             : 
     196             :       // Clear and resize the vector of Aq_representors
     197         568 :       clear_riesz_representors();
     198             : 
     199         568 :       Aq_representor.resize(rb_theta_expansion->get_n_A_terms());
     200        2272 :       for (unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++)
     201             :         {
     202        1752 :           Aq_representor[q_a].resize(Nmax);
     203             :         }
     204             :     }
     205         568 : }
     206             : 
     207     3426803 : NumericVector<Number> & RBEvaluation::get_basis_function(unsigned int i)
     208             : {
     209       97718 :   libmesh_assert_less (i, basis_functions.size());
     210             : 
     211     3524521 :   return *(basis_functions[i]);
     212             : }
     213             : 
     214       56800 : const NumericVector<Number> & RBEvaluation::get_basis_function(unsigned int i) const
     215             : {
     216        1600 :   libmesh_assert_less (i, basis_functions.size());
     217             : 
     218       58400 :   return *(basis_functions[i]);
     219             : }
     220             : 
     221      384914 : Real RBEvaluation::rb_solve(unsigned int N)
     222             : {
     223      384914 :   return rb_solve(N, nullptr);
     224             : }
     225             : 
     226      384914 : Real RBEvaluation::rb_solve(unsigned int N,
     227             :                             const std::vector<Number> * evaluated_thetas)
     228             : {
     229       64012 :   LOG_SCOPE("rb_solve()", "RBEvaluation");
     230             : 
     231      384914 :   libmesh_error_msg_if(N > get_n_basis_functions(),
     232             :                        "ERROR: N cannot be larger than the number of basis functions in rb_solve");
     233             : 
     234             :   // In case the theta functions have been pre-evaluated, first check the size for consistency. The
     235             :   // size of the input "evaluated_thetas" vector must match the sum of the "A", "F", and "output" terms
     236             :   // in the expansion.
     237      384914 :   this->check_evaluated_thetas_size(evaluated_thetas);
     238             : 
     239      384914 :   const RBParameters & mu = get_parameters();
     240             : 
     241             :   // Resize (and clear) the solution vector
     242      352908 :   RB_solution.resize(N);
     243             : 
     244             :   // Assemble the RB system
     245      448926 :   DenseMatrix<Number> RB_system_matrix(N,N);
     246       32006 :   RB_system_matrix.zero();
     247             : 
     248      448926 :   DenseMatrix<Number> RB_Aq_a;
     249     1539656 :   for (unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++)
     250             :     {
     251     1250760 :       RB_Aq_vector[q_a].get_principal_submatrix(N, RB_Aq_a);
     252             : 
     253     1154742 :       if (evaluated_thetas)
     254           0 :         RB_system_matrix.add((*evaluated_thetas)[q_a], RB_Aq_a);
     255             :       else
     256     1154742 :         RB_system_matrix.add(rb_theta_expansion->eval_A_theta(q_a, mu), RB_Aq_a);
     257             :     }
     258             : 
     259             :   // Assemble the RB rhs
     260      384914 :   DenseVector<Number> RB_rhs(N);
     261       32006 :   RB_rhs.zero();
     262             : 
     263      384914 :   DenseVector<Number> RB_Fq_f;
     264     2570538 :   for (unsigned int q_f=0; q_f<rb_theta_expansion->get_n_F_terms(); q_f++)
     265             :     {
     266     2367650 :       RB_Fq_vector[q_f].get_principal_subvector(N, RB_Fq_f);
     267             : 
     268     2185624 :       if (evaluated_thetas)
     269           0 :         RB_rhs.add((*evaluated_thetas)[q_f+rb_theta_expansion->get_n_A_terms()], RB_Fq_f);
     270             :       else
     271     2185624 :         RB_rhs.add(rb_theta_expansion->eval_F_theta(q_f, mu), RB_Fq_f);
     272             :     }
     273             : 
     274             :   // Solve the linear system
     275      384914 :   if (N > 0)
     276             :     {
     277      359614 :       RB_system_matrix.lu_solve(RB_rhs, RB_solution);
     278             :     }
     279             : 
     280             :   // Place to store the output of get_principal_subvector() calls
     281      384914 :   DenseVector<Number> RB_output_vector_N;
     282             : 
     283             :   // Evaluate RB outputs
     284       32006 :   unsigned int output_counter = 0;
     285      484002 :   for (unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++)
     286             :     {
     287      107096 :       RB_outputs[n] = 0.;
     288      198176 :       for (unsigned int q_l=0; q_l<rb_theta_expansion->get_n_output_terms(n); q_l++)
     289             :         {
     290      115104 :           RB_output_vectors[n][q_l].get_principal_subvector(N, RB_output_vector_N);
     291             : 
     292             :           // Compute dot product with current output vector and RB_solution
     293       99088 :           auto dot_prod = RB_output_vector_N.dot(RB_solution);
     294             : 
     295             :           // Determine the coefficient depending on whether or not
     296             :           // pre-evaluated thetas were provided. Note that if
     297             :           // pre-evaluated thetas were provided, they must come after
     298             :           // the "A" and "F" thetas and be in "row-major" order. In
     299             :           // other words, there is a possibly "ragged" 2D array of
     300             :           // output thetas ordered by output index "n" and term index
     301             :           // "q_l" which is accessed in row-major order.
     302       99088 :           auto coeff = evaluated_thetas ?
     303           0 :             (*evaluated_thetas)[output_counter + rb_theta_expansion->get_n_A_terms() + rb_theta_expansion->get_n_F_terms()] :
     304       99088 :             rb_theta_expansion->eval_output_theta(n, q_l, mu);
     305             : 
     306             :           // Finally, accumulate the result in RB_outputs[n]
     307       91084 :           RB_outputs[n] += coeff * dot_prod;
     308             : 
     309             :           // Go to next output
     310       99088 :           output_counter++;
     311             :         }
     312             :     }
     313             : 
     314      384914 :   if (evaluate_RB_error_bound) // Calculate the error bounds
     315             :     {
     316             :       // Evaluate the dual norm of the residual for RB_solution_vector
     317      384914 :       Real epsilon_N = compute_residual_dual_norm(N, evaluated_thetas);
     318             : 
     319             :       // Get lower bound for coercivity constant
     320      384914 :       const Real alpha_LB = get_stability_lower_bound();
     321             :       // alpha_LB needs to be positive to get a valid error bound
     322       32006 :       libmesh_assert_greater ( alpha_LB, 0. );
     323             : 
     324             :       // Evaluate the (absolute) error bound
     325      384914 :       Real abs_error_bound = epsilon_N / residual_scaling_denom(alpha_LB);
     326             : 
     327             :       // Now compute the output error bounds
     328      484002 :       for (unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++)
     329       99088 :         RB_output_error_bounds[n] = abs_error_bound * this->eval_output_dual_norm(n, evaluated_thetas);
     330             : 
     331       32006 :       return abs_error_bound;
     332             :     }
     333             :   else // Don't calculate the error bounds
     334             :     {
     335             :       // Just return -1. if we did not compute the error bound
     336           0 :       return -1.;
     337             :     }
     338      320902 : }
     339             : 
     340           0 : Real RBEvaluation::get_error_bound_normalization()
     341             : {
     342             :   // Normalize the error based on the error bound in the
     343             :   // case of an empty reduced basis. The error bound is based
     344             :   // on the residual F - AU, so with an empty basis this gives
     345             :   // a value based on the norm of F at the current parameters.
     346             : 
     347           0 :   Real normalization = rb_solve(0);
     348           0 :   return normalization;
     349             : }
     350             : 
     351           0 : Real RBEvaluation::compute_residual_dual_norm(const unsigned int N)
     352             : {
     353           0 :   return compute_residual_dual_norm(N, nullptr);
     354             : }
     355             : 
     356      384914 : Real RBEvaluation::compute_residual_dual_norm(const unsigned int N,
     357             :                                               const std::vector<Number> * evaluated_thetas)
     358             : {
     359       64012 :   LOG_SCOPE("compute_residual_dual_norm()", "RBEvaluation");
     360             : 
     361             :   // In case the theta functions have been pre-evaluated, first check the size for consistency
     362      384914 :   this->check_evaluated_thetas_size(evaluated_thetas);
     363             : 
     364             :   // If evaluated_thetas is provided, then mu is not actually used for anything
     365      384914 :   const RBParameters & mu = get_parameters();
     366             : 
     367      384914 :   const unsigned int n_A_terms = rb_theta_expansion->get_n_A_terms();
     368      384914 :   const unsigned int n_F_terms = rb_theta_expansion->get_n_F_terms();
     369             : 
     370             :   // Use the stored representor inner product values
     371             :   // to evaluate the residual norm
     372       64009 :   Number residual_norm_sq = 0.;
     373             : 
     374             :   // Lambdas to help with evaluating F_theta and A_theta functions
     375             :   // using either the pre-evaluated thetas (if provided) or by calling
     376             :   // eval_{F,A}_theta()
     377    11959002 :   auto eval_F = [&](unsigned int index)
     378             :     {
     379    11959002 :       return (evaluated_thetas) ? (*evaluated_thetas)[index + n_A_terms] : rb_theta_expansion->eval_F_theta(index, mu);
     380      384914 :     };
     381    10021098 :   auto eval_A = [&](unsigned int index)
     382             :     {
     383    10021098 :       return (evaluated_thetas) ? (*evaluated_thetas)[index] : rb_theta_expansion->eval_A_theta(index, mu);
     384      384914 :     };
     385             : 
     386       32006 :   unsigned int q=0;
     387     2570538 :   for (unsigned int q_f1=0; q_f1<n_F_terms; q_f1++)
     388             :     {
     389     2185624 :       const Number val_q_f1 = eval_F(q_f1);
     390             : 
     391     9773378 :       for (unsigned int q_f2=q_f1; q_f2<n_F_terms; q_f2++)
     392             :         {
     393     7587754 :           const Number val_q_f2 = eval_F(q_f2);
     394             : 
     395     7587754 :           Real delta = (q_f1==q_f2) ? 1. : 2.;
     396     7587754 :           residual_norm_sq += delta * libmesh_real(val_q_f1 * libmesh_conj(val_q_f2) * Fq_representor_innerprods[q] );
     397             : 
     398     7587754 :           q++;
     399             :         }
     400             :     }
     401             : 
     402     2570538 :   for (unsigned int q_f=0; q_f<n_F_terms; q_f++)
     403             :     {
     404     2185624 :       const Number val_q_f = eval_F(q_f);
     405             : 
     406     8742496 :       for (unsigned int q_a=0; q_a<n_A_terms; q_a++)
     407             :         {
     408     6556872 :           const Number val_q_a = eval_A(q_a);
     409             : 
     410    52649790 :           for (unsigned int i=0; i<N; i++)
     411             :             {
     412     3838200 :               Real delta = 2.;
     413    42255318 :               residual_norm_sq +=
     414    49931718 :                 delta * libmesh_real( val_q_f * libmesh_conj(val_q_a) *
     415    53769318 :                                       libmesh_conj(RB_solution(i)) * Fq_Aq_representor_innerprods[q_f][q_a][i] );
     416             :             }
     417             :         }
     418             :     }
     419             : 
     420       32006 :   q=0;
     421     1539656 :   for (unsigned int q_a1=0; q_a1<n_A_terms; q_a1++)
     422             :     {
     423     1154742 :       const Number val_q_a1 = eval_A(q_a1);
     424             : 
     425     3464226 :       for (unsigned int q_a2=q_a1; q_a2<n_A_terms; q_a2++)
     426             :         {
     427     2309484 :           const Number val_q_a2 = eval_A(q_a2);
     428             : 
     429     2309484 :           Real delta = (q_a1==q_a2) ? 1. : 2.;
     430             : 
     431    18831420 :           for (unsigned int i=0; i<N; i++)
     432             :             {
     433   180882852 :               for (unsigned int j=0; j<N; j++)
     434             :                 {
     435   150693816 :                   residual_norm_sq +=
     436   178038216 :                     delta * libmesh_real( libmesh_conj(val_q_a1) * val_q_a2 *
     437   205377516 :                                           libmesh_conj(RB_solution(i)) * RB_solution(j) * Aq_Aq_representor_innerprods[q][i][j] );
     438             :                 }
     439             :             }
     440             : 
     441     2309484 :           q++;
     442             :         }
     443             :     }
     444             : 
     445      384914 :   if (libmesh_real(residual_norm_sq) < 0.)
     446             :     {
     447             :       //    libMesh::out << "Warning: Square of residual norm is negative "
     448             :       //                 << "in RBSystem::compute_residual_dual_norm()" << std::endl;
     449             : 
     450             :       //     Sometimes this is negative due to rounding error,
     451             :       //     but when this occurs the error is on the order of 1.e-10,
     452             :       //     so shouldn't affect error bound much...
     453         133 :       residual_norm_sq = std::abs(residual_norm_sq);
     454             :     }
     455             : 
     456      416920 :   return std::sqrt( libmesh_real(residual_norm_sq) );
     457             : }
     458             : 
     459           0 : Real RBEvaluation::get_stability_lower_bound()
     460             : {
     461             :   // Return a default value of 1, this function should
     462             :   // be overloaded to specify a problem-dependent stability
     463             :   // factor lower bound
     464           0 :   return 1.;
     465             : }
     466             : 
     467     2591914 : Real RBEvaluation::residual_scaling_denom(Real alpha_LB)
     468             : {
     469             :   // Here we implement the residual scaling for a coercive
     470             :   // problem.
     471     2591914 :   return alpha_LB;
     472             : }
     473             : 
     474             : #ifdef LIBMESH_ENABLE_DEPRECATED
     475           0 : Real RBEvaluation::eval_output_dual_norm(unsigned int n, const RBParameters & /*mu*/)
     476             : {
     477             :   libmesh_deprecated();
     478             : 
     479             :   // Call non-deprecated version of this function, ignoring input mu
     480           0 :   return this->eval_output_dual_norm(n, nullptr);
     481             : }
     482             : #endif // LIBMESH_ENABLE_DEPRECATED
     483             : 
     484     9015368 : Real RBEvaluation::eval_output_dual_norm(unsigned int n,
     485             :                                          const std::vector<Number> * evaluated_thetas)
     486             : {
     487             :   // Return value
     488      824820 :   Number output_bound_sq = 0.;
     489             : 
     490             :   // mu is only used if evaluated_thetas == nullptr
     491     9015368 :   const RBParameters & mu = this->get_parameters();
     492             : 
     493             :   // Index into output_dual_innerprods
     494      816816 :   unsigned int q=0;
     495    18030736 :   for (unsigned int q_l1=0; q_l1<rb_theta_expansion->get_n_output_terms(n); q_l1++)
     496             :     {
     497    18030736 :       for (unsigned int q_l2=q_l1; q_l2<rb_theta_expansion->get_n_output_terms(n); q_l2++)
     498             :         {
     499     9015368 :           Real delta = (q_l1==q_l2) ? 1. : 2.;
     500             : 
     501             :           Number val_l1 =
     502     9015368 :             evaluated_thetas ?
     503           0 :             (*evaluated_thetas)[rb_theta_expansion->output_index_1D(n, q_l1) + rb_theta_expansion->get_n_A_terms() + rb_theta_expansion->get_n_F_terms()] :
     504     9015368 :             rb_theta_expansion->eval_output_theta(n, q_l1, mu);
     505             : 
     506             :           Number val_l2 =
     507     1633632 :             evaluated_thetas ?
     508           0 :             (*evaluated_thetas)[rb_theta_expansion->output_index_1D(n, q_l2) + rb_theta_expansion->get_n_A_terms() + rb_theta_expansion->get_n_F_terms()] :
     509     9015368 :             rb_theta_expansion->eval_output_theta(n, q_l2, mu);
     510             : 
     511     9007364 :           output_bound_sq += delta * libmesh_real(
     512     9832184 :             libmesh_conj(val_l1) * val_l2 * output_dual_innerprods[n][q]);
     513             : 
     514     9015368 :           q++;
     515             :         }
     516             :     }
     517             : 
     518     9015368 :   return libmesh_real(std::sqrt( output_bound_sq ));
     519             : }
     520             : 
     521         568 : void RBEvaluation::clear_riesz_representors()
     522             : {
     523         552 :   Aq_representor.clear();
     524         568 : }
     525             : 
     526         284 : void RBEvaluation::legacy_write_offline_data_to_files(const std::string & directory_name,
     527             :                                                       const bool write_binary_data)
     528             : {
     529          16 :   LOG_SCOPE("legacy_write_offline_data_to_files()", "RBEvaluation");
     530             : 
     531             :   // Get the number of basis functions
     532         284 :   unsigned int n_bfs = get_n_basis_functions();
     533             : 
     534             :   // The writing mode: ENCODE for binary, WRITE for ASCII
     535         284 :   XdrMODE mode = write_binary_data ? ENCODE : WRITE;
     536             : 
     537             :   // The suffix to use for all the files that are written out
     538         292 :   const std::string suffix = write_binary_data ? ".xdr" : ".dat";
     539             : 
     540         292 :   if (this->processor_id() == 0)
     541             :     {
     542             : 
     543             :       // Make a directory to store all the data files
     544          48 :       Utility::mkdir(directory_name.c_str());
     545             :       //    if (mkdir(directory_name.c_str(), 0777) == -1)
     546             :       //    {
     547             :       //      libMesh::out << "In RBEvaluation::write_offline_data_to_files, directory "
     548             :       //                   << directory_name << " already exists, overwriting contents." << std::endl;
     549             :       //    }
     550             : 
     551             :       // First, write out how many basis functions we have generated
     552          56 :       std::ostringstream file_name;
     553             :       {
     554          44 :         file_name << directory_name << "/n_bfs" << suffix;
     555          96 :         Xdr n_bfs_out(file_name.str(), mode);
     556           8 :         n_bfs_out << n_bfs;
     557          48 :         n_bfs_out.close();
     558          40 :       }
     559             : 
     560             :       // Write out the parameter ranges
     561          92 :       file_name.str("");
     562          44 :       file_name << directory_name << "/parameter_ranges" << suffix;
     563           8 :       std::string continuous_param_file_name = file_name.str();
     564             : 
     565             :       // Write out the discrete parameter values
     566          92 :       file_name.str("");
     567          44 :       file_name << directory_name << "/discrete_parameter_values" << suffix;
     568           8 :       std::string discrete_param_file_name = file_name.str();
     569             : 
     570          48 :       write_parameter_data_to_files(continuous_param_file_name,
     571             :                                     discrete_param_file_name,
     572             :                                     write_binary_data);
     573             : 
     574             :       // Write out Fq representor norm data
     575          92 :       file_name.str("");
     576          44 :       file_name << directory_name << "/Fq_innerprods" << suffix;
     577          56 :       Xdr RB_Fq_innerprods_out(file_name.str(), mode);
     578          48 :       unsigned int Q_f_hat = rb_theta_expansion->get_n_F_terms()*(rb_theta_expansion->get_n_F_terms()+1)/2;
     579         576 :       for (unsigned int i=0; i<Q_f_hat; i++)
     580             :         {
     581         572 :           RB_Fq_innerprods_out << Fq_representor_innerprods[i];
     582             :         }
     583          48 :       RB_Fq_innerprods_out.close();
     584             : 
     585             :       // Write out output data
     586         144 :       for (unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++)
     587             :         {
     588         184 :           file_name.str("");
     589          96 :           file_name << directory_name << "/output_";
     590             :           file_name << std::setw(3)
     591             :                     << std::setprecision(0)
     592           8 :                     << std::setfill('0')
     593           8 :                     << std::right
     594           8 :                     << n;
     595             : 
     596          88 :           file_name << "_dual_innerprods" << suffix;
     597         112 :           Xdr output_dual_innerprods_out(file_name.str(), mode);
     598             : 
     599          96 :           unsigned int Q_l_hat = rb_theta_expansion->get_n_output_terms(n)*(rb_theta_expansion->get_n_output_terms(n)+1)/2;
     600         192 :           for (unsigned int q=0; q<Q_l_hat; q++)
     601             :             {
     602         112 :               output_dual_innerprods_out << output_dual_innerprods[n][q];
     603             :             }
     604          96 :           output_dual_innerprods_out.close();
     605          80 :         }
     606             : 
     607             : 
     608             :       // Write out output data to multiple files
     609         144 :       for (unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++)
     610             :         {
     611         192 :           for (unsigned int q_l=0; q_l<rb_theta_expansion->get_n_output_terms(n); q_l++)
     612             :             {
     613         184 :               file_name.str("");
     614          96 :               file_name << directory_name << "/output_";
     615             :               file_name << std::setw(3)
     616             :                         << std::setprecision(0)
     617           8 :                         << std::setfill('0')
     618           8 :                         << std::right
     619           8 :                         << n;
     620          96 :               file_name << "_";
     621             :               file_name << std::setw(3)
     622             :                         << std::setprecision(0)
     623           8 :                         << std::setfill('0')
     624           8 :                         << std::right
     625           8 :                         << q_l;
     626           8 :               file_name << suffix;
     627         120 :               Xdr output_n_out(file_name.str(), mode);
     628             : 
     629        1960 :               for (unsigned int j=0; j<n_bfs; j++)
     630             :                 {
     631         640 :                   output_n_out << RB_output_vectors[n][q_l](j);
     632             :                 }
     633          96 :               output_n_out.close();
     634          80 :             }
     635             :         }
     636             : 
     637          48 :       if (compute_RB_inner_product)
     638             :         {
     639             :           // Next write out the inner product matrix
     640          21 :           file_name.str("");
     641          10 :           file_name << directory_name << "/RB_inner_product_matrix" << suffix;
     642          14 :           Xdr RB_inner_product_matrix_out(file_name.str(), mode);
     643         231 :           for (unsigned int i=0; i<n_bfs; i++)
     644             :             {
     645        4620 :               for (unsigned int j=0; j<n_bfs; j++)
     646             :                 {
     647         800 :                   RB_inner_product_matrix_out << RB_inner_product_matrix(i,j);
     648             :                 }
     649             :             }
     650          11 :           RB_inner_product_matrix_out.close();
     651           9 :         }
     652             : 
     653             :       // Next write out the Fq vectors
     654         216 :       for (unsigned int q_f=0; q_f<rb_theta_expansion->get_n_F_terms(); q_f++)
     655             :         {
     656         322 :           file_name.str("");
     657         168 :           file_name << directory_name << "/RB_F_";
     658             :           file_name << std::setw(3)
     659             :                     << std::setprecision(0)
     660          14 :                     << std::setfill('0')
     661          14 :                     << std::right
     662          14 :                     << q_f;
     663          14 :           file_name << suffix;
     664         210 :           Xdr RB_Fq_f_out(file_name.str(), mode);
     665             : 
     666        2794 :           for (unsigned int i=0; i<n_bfs; i++)
     667             :             {
     668         660 :               RB_Fq_f_out << RB_Fq_vector[q_f](i);
     669             :             }
     670         168 :           RB_Fq_f_out.close();
     671         140 :         }
     672             : 
     673             :       // Next write out the Aq matrices
     674         192 :       for (unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++)
     675             :         {
     676         276 :           file_name.str("");
     677         144 :           file_name << directory_name << "/RB_A_";
     678             :           file_name << std::setw(3)
     679             :                     << std::setprecision(0)
     680          12 :                     << std::setfill('0')
     681          12 :                     << std::right
     682          12 :                     << q_a;
     683          12 :           file_name << suffix;
     684         180 :           Xdr RB_Aq_a_out(file_name.str(), mode);
     685             : 
     686        2622 :           for (unsigned int i=0; i<n_bfs; i++)
     687             :             {
     688       46386 :               for (unsigned int j=0; j<n_bfs; j++)
     689             :                 {
     690       11250 :                   RB_Aq_a_out << RB_Aq_vector[q_a](i,j);
     691             :                 }
     692             :             }
     693         144 :           RB_Aq_a_out.close();
     694         120 :         }
     695             : 
     696             :       // Next write out Fq_Aq representor norm data
     697          92 :       file_name.str("");
     698          44 :       file_name << directory_name << "/Fq_Aq_innerprods" << suffix;
     699          60 :       Xdr RB_Fq_Aq_innerprods_out(file_name.str(), mode);
     700             : 
     701         216 :       for (unsigned int q_f=0; q_f<rb_theta_expansion->get_n_F_terms(); q_f++)
     702             :         {
     703         672 :           for (unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++)
     704             :             {
     705        8382 :               for (unsigned int i=0; i<n_bfs; i++)
     706             :                 {
     707        9858 :                   RB_Fq_Aq_innerprods_out << Fq_Aq_representor_innerprods[q_f][q_a][i];
     708             :                 }
     709             :             }
     710             :         }
     711          48 :       RB_Fq_Aq_innerprods_out.close();
     712             : 
     713             :       // Next write out Aq_Aq representor norm data
     714          92 :       file_name.str("");
     715          44 :       file_name << directory_name << "/Aq_Aq_innerprods" << suffix;
     716          56 :       Xdr RB_Aq_Aq_innerprods_out(file_name.str(), mode);
     717             : 
     718          48 :       unsigned int Q_a_hat = rb_theta_expansion->get_n_A_terms()*(rb_theta_expansion->get_n_A_terms()+1)/2;
     719         336 :       for (unsigned int i=0; i<Q_a_hat; i++)
     720             :         {
     721        5244 :           for (unsigned int j=0; j<n_bfs; j++)
     722             :             {
     723       92772 :               for (unsigned int l=0; l<n_bfs; l++)
     724             :                 {
     725      110316 :                   RB_Aq_Aq_innerprods_out << Aq_Aq_representor_innerprods[i][j][l];
     726             :                 }
     727             :             }
     728             :         }
     729          48 :       RB_Aq_Aq_innerprods_out.close();
     730             : 
     731             :       // Also, write out the greedily selected parameters
     732             :       {
     733          92 :         file_name.str("");
     734          44 :         file_name << directory_name << "/greedy_params" << suffix;
     735         100 :         Xdr greedy_params_out(file_name.str(), mode);
     736             : 
     737         922 :         for (const auto & param : greedy_param_list)
     738        4549 :           for (const auto & pr : param)
     739        7350 :             for (const auto & value_vector : pr.second)
     740             :               {
     741             :                 // Need to make a copy of the value so that it's not const
     742             :                 // Xdr is not templated on const's
     743        3983 :                 libmesh_error_msg_if(value_vector.size() != 1,
     744             :                                      "Error: multi-value RB parameters are not yet supported here.");
     745        3675 :                 Real param_value = value_vector[0];
     746         616 :                 greedy_params_out << param_value;
     747             :               }
     748          48 :         greedy_params_out.close();
     749          40 :       }
     750             : 
     751          80 :     }
     752         284 : }
     753             : 
     754         284 : void RBEvaluation::legacy_read_offline_data_from_files(const std::string & directory_name,
     755             :                                                        bool read_error_bound_data,
     756             :                                                        const bool read_binary_data)
     757             : {
     758          16 :   LOG_SCOPE("legacy_read_offline_data_from_files()", "RBEvaluation");
     759             : 
     760             :   // The reading mode: DECODE for binary, READ for ASCII
     761         284 :   XdrMODE mode = read_binary_data ? DECODE : READ;
     762             : 
     763             :   // The suffix to use for all the files that are written out
     764         292 :   const std::string suffix = read_binary_data ? ".xdr" : ".dat";
     765             : 
     766             :   // The string stream we'll use to make the file names
     767         300 :   std::ostringstream file_name;
     768             : 
     769             :   // First, find out how many basis functions we had when Greedy terminated
     770             :   unsigned int n_bfs;
     771             :   {
     772         276 :     file_name << directory_name << "/n_bfs" << suffix;
     773         560 :     assert_file_exists(file_name.str());
     774             : 
     775         568 :     Xdr n_bfs_in(file_name.str(), mode);
     776          16 :     n_bfs_in >> n_bfs;
     777         284 :     n_bfs_in.close();
     778         268 :   }
     779         284 :   resize_data_structures(n_bfs, read_error_bound_data);
     780             : 
     781             :   // Read in the parameter ranges
     782         560 :   file_name.str("");
     783         276 :   file_name << directory_name << "/parameter_ranges" << suffix;
     784          16 :   std::string continuous_param_file_name = file_name.str();
     785             : 
     786             :   // Read in the discrete parameter values
     787         560 :   file_name.str("");
     788         276 :   file_name << directory_name << "/discrete_parameter_values" << suffix;
     789          16 :   std::string discrete_param_file_name = file_name.str();
     790         284 :   read_parameter_data_from_files(continuous_param_file_name,
     791             :                                  discrete_param_file_name,
     792             :                                  read_binary_data);
     793             : 
     794             :   // Read in output data in multiple files
     795         852 :   for (unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++)
     796             :     {
     797        1136 :       for (unsigned int q_l=0; q_l<rb_theta_expansion->get_n_output_terms(n); q_l++)
     798             :         {
     799        1120 :           file_name.str("");
     800         568 :           file_name << directory_name << "/output_";
     801             :           file_name << std::setw(3)
     802             :                     << std::setprecision(0)
     803          16 :                     << std::setfill('0')
     804          16 :                     << std::right
     805          16 :                     << n;
     806         568 :           file_name << "_";
     807             :           file_name << std::setw(3)
     808             :                     << std::setprecision(0)
     809          16 :                     << std::setfill('0')
     810          16 :                     << std::right
     811          16 :                     << q_l;
     812          16 :           file_name << suffix;
     813        1120 :           assert_file_exists(file_name.str());
     814             : 
     815         616 :           Xdr output_n_in(file_name.str(), mode);
     816             : 
     817       11872 :           for (unsigned int j=0; j<n_bfs; j++)
     818             :             {
     819          80 :               Number value;
     820         640 :               output_n_in >> value;
     821       11944 :               RB_output_vectors[n][q_l](j) = value;
     822             :             }
     823         568 :           output_n_in.close();
     824         536 :         }
     825             :     }
     826             : 
     827         284 :   if (compute_RB_inner_product)
     828             :     {
     829             :       // Next read in the inner product matrix
     830         138 :       file_name.str("");
     831          68 :       file_name << directory_name << "/RB_inner_product_matrix" << suffix;
     832         138 :       assert_file_exists(file_name.str());
     833             : 
     834          76 :       Xdr RB_inner_product_matrix_in(file_name.str(), mode);
     835             : 
     836        1470 :       for (unsigned int i=0; i<n_bfs; i++)
     837             :         {
     838       29400 :           for (unsigned int j=0; j<n_bfs; j++)
     839             :             {
     840           0 :               Number value;
     841        1600 :               RB_inner_product_matrix_in >> value;
     842       28800 :               RB_inner_product_matrix(i,j) = value;
     843             :             }
     844             :         }
     845          70 :       RB_inner_product_matrix_in.close();
     846          66 :     }
     847             : 
     848             :   // Next read in the Fq vectors
     849        1278 :   for (unsigned int q_f=0; q_f<rb_theta_expansion->get_n_F_terms(); q_f++)
     850             :     {
     851        1960 :       file_name.str("");
     852         994 :       file_name << directory_name << "/RB_F_";
     853             :       file_name << std::setw(3)
     854             :                 << std::setprecision(0)
     855          28 :                 << std::setfill('0')
     856          28 :                 << std::right
     857          28 :                 << q_f;
     858          28 :       file_name << suffix;
     859        1960 :       assert_file_exists(file_name.str());
     860             : 
     861        1078 :       Xdr RB_Fq_f_in(file_name.str(), mode);
     862             : 
     863       16600 :       for (unsigned int i=0; i<n_bfs; i++)
     864             :         {
     865         200 :           Number value;
     866         880 :           RB_Fq_f_in >> value;
     867       16046 :           RB_Fq_vector[q_f](i) = value;
     868             :         }
     869         994 :       RB_Fq_f_in.close();
     870         938 :     }
     871             : 
     872             :   // Next read in the Aq matrices
     873        1136 :   for (unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++)
     874             :     {
     875        1680 :       file_name.str("");
     876         852 :       file_name << directory_name << "/RB_A_";
     877             :       file_name << std::setw(3)
     878             :                 << std::setprecision(0)
     879          24 :                 << std::setfill('0')
     880          24 :                 << std::right
     881          24 :                 << q_a;
     882          24 :       file_name << suffix;
     883        1680 :       assert_file_exists(file_name.str());
     884             : 
     885         924 :       Xdr RB_Aq_a_in(file_name.str(), mode);
     886             : 
     887       15720 :       for (unsigned int i=0; i<n_bfs; i++)
     888             :         {
     889      280026 :           for (unsigned int j=0; j<n_bfs; j++)
     890             :             {
     891        2550 :               Number  value;
     892       15000 :               RB_Aq_a_in >> value;
     893      272658 :               RB_Aq_vector[q_a](i,j) = value;
     894             :             }
     895             :         }
     896         852 :       RB_Aq_a_in.close();
     897         804 :     }
     898             : 
     899             : 
     900         284 :   if (read_error_bound_data)
     901             :     {
     902             :       // Next read in Fq representor norm data
     903         560 :       file_name.str("");
     904         276 :       file_name << directory_name << "/Fq_innerprods" << suffix;
     905         560 :       assert_file_exists(file_name.str());
     906             : 
     907         300 :       Xdr RB_Fq_innerprods_in(file_name.str(), mode);
     908             : 
     909         284 :       unsigned int Q_f_hat = rb_theta_expansion->get_n_F_terms()*(rb_theta_expansion->get_n_F_terms()+1)/2;
     910        3408 :       for (unsigned int i=0; i<Q_f_hat; i++)
     911             :         {
     912        3212 :           RB_Fq_innerprods_in >> Fq_representor_innerprods[i];
     913             :         }
     914         284 :       RB_Fq_innerprods_in.close();
     915             : 
     916             :       // Read in output data
     917         852 :       for (unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++)
     918             :         {
     919        1120 :           file_name.str("");
     920         568 :           file_name << directory_name << "/output_";
     921             :           file_name << std::setw(3)
     922             :                     << std::setprecision(0)
     923          16 :                     << std::setfill('0')
     924          16 :                     << std::right
     925          16 :                     << n;
     926         552 :           file_name << "_dual_innerprods" << suffix;
     927        1120 :           assert_file_exists(file_name.str());
     928             : 
     929         600 :           Xdr output_dual_innerprods_in(file_name.str(), mode);
     930             : 
     931         568 :           unsigned int Q_l_hat = rb_theta_expansion->get_n_output_terms(n)*(rb_theta_expansion->get_n_output_terms(n)+1)/2;
     932        1136 :           for (unsigned int q=0; q<Q_l_hat; q++)
     933             :             {
     934         600 :               output_dual_innerprods_in >> output_dual_innerprods[n][q];
     935             :             }
     936         568 :           output_dual_innerprods_in.close();
     937         536 :         }
     938             : 
     939             : 
     940             :       // Next read in Fq_Aq representor norm data
     941         560 :       file_name.str("");
     942         276 :       file_name << directory_name << "/Fq_Aq_innerprods" << suffix;
     943         560 :       assert_file_exists(file_name.str());
     944             : 
     945         308 :       Xdr RB_Fq_Aq_innerprods_in(file_name.str(), mode);
     946             : 
     947        1278 :       for (unsigned int q_f=0; q_f<rb_theta_expansion->get_n_F_terms(); q_f++)
     948             :         {
     949        3976 :           for (unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++)
     950             :             {
     951       49800 :               for (unsigned int i=0; i<n_bfs; i++)
     952             :                 {
     953       50778 :                   RB_Fq_Aq_innerprods_in >> Fq_Aq_representor_innerprods[q_f][q_a][i];
     954             :                 }
     955             :             }
     956             :         }
     957         284 :       RB_Fq_Aq_innerprods_in.close();
     958             : 
     959             :       // Next read in Aq_Aq representor norm data
     960         560 :       file_name.str("");
     961         276 :       file_name << directory_name << "/Aq_Aq_innerprods" << suffix;
     962         560 :       assert_file_exists(file_name.str());
     963             : 
     964         300 :       Xdr RB_Aq_Aq_innerprods_in(file_name.str(), mode);
     965             : 
     966         284 :       unsigned int Q_a_hat = rb_theta_expansion->get_n_A_terms()*(rb_theta_expansion->get_n_A_terms()+1)/2;
     967        1988 :       for (unsigned int i=0; i<Q_a_hat; i++)
     968             :         {
     969       31440 :           for (unsigned int j=0; j<n_bfs; j++)
     970             :             {
     971      560052 :               for (unsigned int l=0; l<n_bfs; l++)
     972             :                 {
     973      575316 :                   RB_Aq_Aq_innerprods_in >> Aq_Aq_representor_innerprods[i][j][l];
     974             :                 }
     975             :             }
     976             :         }
     977         284 :       RB_Aq_Aq_innerprods_in.close();
     978         268 :     }
     979             : 
     980             :   // Resize basis_functions even if we don't read them in so that
     981             :   // get_n_bfs() returns the correct value. Initialize the pointers
     982             :   // to nullptr.
     983         276 :   basis_functions.clear();
     984         284 :   set_n_basis_functions(n_bfs);
     985         552 : }
     986             : 
     987        5032 : void RBEvaluation::assert_file_exists(const std::string & file_name)
     988             : {
     989        5032 :   libmesh_error_msg_if(!std::ifstream(file_name.c_str()), "File missing: " << file_name);
     990        5032 : }
     991             : 
     992         284 : void RBEvaluation::write_out_basis_functions(System & sys,
     993             :                                              const std::string & directory_name,
     994             :                                              const bool write_binary_basis_functions)
     995             : {
     996          16 :   LOG_SCOPE("write_out_basis_functions()", "RBEvaluation");
     997             : 
     998           8 :   std::vector<NumericVector<Number>*> basis_functions_ptrs;
     999        5388 :   for (std::size_t i=0; i<basis_functions.size(); i++)
    1000             :   {
    1001        4956 :     basis_functions_ptrs.push_back(basis_functions[i].get());
    1002             :   }
    1003             : 
    1004         560 :   write_out_vectors(sys,
    1005             :                     basis_functions_ptrs,
    1006             :                     directory_name,
    1007             :                     "bf",
    1008             :                     write_binary_basis_functions);
    1009         284 : }
    1010             : 
    1011         284 : void RBEvaluation::write_out_vectors(System & sys,
    1012             :                                      std::vector<NumericVector<Number>*> & vectors,
    1013             :                                      const std::string & directory_name,
    1014             :                                      const std::string & data_name,
    1015             :                                      const bool write_binary_vectors)
    1016             : {
    1017          16 :   LOG_SCOPE("write_out_vectors()", "RBEvaluation");
    1018             : 
    1019         284 :   if (sys.comm().rank() == 0)
    1020             :     {
    1021             :       // Make a directory to store all the data files
    1022          48 :       Utility::mkdir(directory_name.c_str());
    1023             :     }
    1024             : 
    1025             :   // Make sure processors are synced up before we begin
    1026         284 :   sys.comm().barrier();
    1027             : 
    1028         300 :   std::ostringstream file_name;
    1029         292 :   const std::string basis_function_suffix = (write_binary_vectors ? ".xdr" : ".dat");
    1030             : 
    1031         544 :   file_name << directory_name << "/" << data_name << "_data" << basis_function_suffix;
    1032         276 :   Xdr bf_data(file_name.str(),
    1033         584 :               write_binary_vectors ? ENCODE : WRITE);
    1034             : 
    1035             :   // Following EquationSystems::write(), we should only write the header information
    1036             :   // if we're proc 0
    1037         284 :   if (sys.comm().rank() == 0)
    1038             :     {
    1039          96 :       std::string version("libMesh-" + libMesh::get_io_compatibility_version());
    1040             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
    1041           4 :       version += " with infinite elements";
    1042             : #endif
    1043          48 :       bf_data.data(version ,"# File Format Identifier");
    1044             : 
    1045          48 :       sys.write_header(bf_data, /*(unused arg)*/ version, /*write_additional_data=*/false);
    1046             :     }
    1047             : 
    1048             :   // Following EquationSystemsIO::write, we use a temporary numbering (node major)
    1049             :   // before writing out the data
    1050         284 :   MeshTools::Private::globally_renumber_nodes_and_elements(sys.get_mesh());
    1051             : 
    1052             :   // Write all vectors at once.
    1053             :   {
    1054             :     // Note the API wants pointers to constant vectors, hence this...
    1055          16 :     std::vector<const NumericVector<Number> *> bf_out;
    1056        5240 :     for (const auto & vec : vectors)
    1057        4956 :       bf_out.push_back(vec);
    1058             : 
    1059             :     // for (auto & val : vectors)
    1060             :     //   bf_out.push_back(val);
    1061         284 :     sys.write_serialized_vectors (bf_data, bf_out);
    1062             :   }
    1063             : 
    1064             : 
    1065             :   // set the current version
    1066           8 :   bf_data.set_version(LIBMESH_VERSION_ID(LIBMESH_MAJOR_VERSION,
    1067             :                                          LIBMESH_MINOR_VERSION,
    1068             :                                          LIBMESH_MICRO_VERSION));
    1069             : 
    1070             : 
    1071             :   // Undo the temporary renumbering
    1072         284 :   sys.get_mesh().fix_broken_node_and_element_numbering();
    1073         552 : }
    1074             : 
    1075         284 : void RBEvaluation::read_in_basis_functions(System & sys,
    1076             :                                            const std::string & directory_name,
    1077             :                                            const bool read_binary_basis_functions)
    1078             : {
    1079           8 :   LOG_SCOPE("read_in_basis_functions()", "RBEvaluation");
    1080             : 
    1081         300 :   read_in_vectors(sys,
    1082         284 :                   basis_functions,
    1083             :                   directory_name,
    1084             :                   "bf",
    1085             :                   read_binary_basis_functions);
    1086         284 : }
    1087             : 
    1088         284 : void RBEvaluation::read_in_vectors(System & sys,
    1089             :                                    std::vector<std::unique_ptr<NumericVector<Number>>> & vectors,
    1090             :                                    const std::string & directory_name,
    1091             :                                    const std::string & data_name,
    1092             :                                    const bool read_binary_vectors)
    1093             : {
    1094          16 :   std::vector<std::vector<std::unique_ptr<NumericVector<Number>>> *> vectors_vec;
    1095         284 :   vectors_vec.push_back(&vectors);
    1096             : 
    1097          24 :   std::vector<std::string> directory_name_vec;
    1098         284 :   directory_name_vec.push_back(directory_name);
    1099             : 
    1100          16 :   std::vector<std::string> data_name_vec;
    1101         284 :   data_name_vec.push_back(data_name);
    1102             : 
    1103         292 :   read_in_vectors_from_multiple_files(sys,
    1104             :                                       vectors_vec,
    1105             :                                       directory_name_vec,
    1106             :                                       data_name_vec,
    1107             :                                       read_binary_vectors);
    1108         552 : }
    1109             : 
    1110         284 : void RBEvaluation::read_in_vectors_from_multiple_files(System & sys,
    1111             :                                                        std::vector<std::vector<std::unique_ptr<NumericVector<Number>>> *> multiple_vectors,
    1112             :                                                        const std::vector<std::string> & multiple_directory_names,
    1113             :                                                        const std::vector<std::string> & multiple_data_names,
    1114             :                                                        const bool read_binary_vectors)
    1115             : {
    1116           8 :   LOG_SCOPE("read_in_vectors_from_multiple_files()", "RBEvaluation");
    1117             : 
    1118          16 :   std::size_t n_files = multiple_vectors.size();
    1119          16 :   std::size_t n_directories = multiple_directory_names.size();
    1120           8 :   libmesh_assert((n_files == n_directories) && (n_files == multiple_data_names.size()));
    1121             : 
    1122         284 :   if (n_files == 0)
    1123           0 :     return;
    1124             : 
    1125             :   // Make sure processors are synced up before we begin
    1126         284 :   sys.comm().barrier();
    1127             : 
    1128         300 :   std::ostringstream file_name;
    1129         292 :   const std::string basis_function_suffix = (read_binary_vectors ? ".xdr" : ".dat");
    1130             : 
    1131             :   // Following EquationSystemsIO::read, we use a temporary numbering (node major)
    1132             :   // before writing out the data. For the sake of efficiency, we do this once for
    1133             :   // all the vectors that we read in.
    1134         284 :   MeshTools::Private::globally_renumber_nodes_and_elements(sys.get_mesh());
    1135             : 
    1136         568 :   for (std::size_t data_index=0; data_index<n_directories; data_index++)
    1137             :     {
    1138         292 :       std::vector<std::unique_ptr<NumericVector<Number>>> & vectors = *multiple_vectors[data_index];
    1139             : 
    1140             :       // Allocate storage for each vector
    1141        5240 :       for (auto & vec : vectors)
    1142             :         {
    1143             :           // vectors should all be nullptr, otherwise we get a memory leak when
    1144             :           // we create the new vectors in RBEvaluation::read_in_vectors.
    1145        4956 :           libmesh_error_msg_if(vec, "Non-nullptr vector passed to read_in_vectors_from_multiple_files");
    1146             : 
    1147        9772 :           vec = NumericVector<Number>::build(sys.comm());
    1148             : 
    1149        5096 :           vec->init (sys.n_dofs(),
    1150             :                      sys.n_local_dofs(),
    1151             :                      false,
    1152         280 :                      PARALLEL);
    1153             :         }
    1154             : 
    1155         552 :       file_name.str("");
    1156          16 :       file_name << multiple_directory_names[data_index]
    1157          16 :                 << "/" << multiple_data_names[data_index]
    1158         544 :                 << "_data" << basis_function_suffix;
    1159             : 
    1160             :       // On processor zero check to be sure the file exists
    1161         284 :       if (sys.comm().rank() == 0)
    1162             :         {
    1163             :           struct stat stat_info;
    1164          48 :           int stat_result = stat(file_name.str().c_str(), &stat_info);
    1165             : 
    1166          48 :           libmesh_error_msg_if(stat_result != 0, "File does not exist: " << file_name.str());
    1167             :         }
    1168             : 
    1169         284 :       assert_file_exists(file_name.str());
    1170         284 :       Xdr vector_data(file_name.str(),
    1171         584 :                       read_binary_vectors ? DECODE : READ);
    1172             : 
    1173             :       // Read the header data. This block of code is based on EquationSystems::_read_impl.
    1174             :       {
    1175          16 :         std::string version;
    1176         284 :         vector_data.data(version);
    1177             : 
    1178         292 :         const std::string libMesh_label = "libMesh-";
    1179           8 :         std::string::size_type lm_pos = version.find(libMesh_label);
    1180         284 :         libmesh_error_msg_if(lm_pos == std::string::npos, "version info missing in Xdr header");
    1181             : 
    1182         300 :         std::istringstream iss(version.substr(lm_pos + libMesh_label.size()));
    1183         284 :         int ver_major = 0, ver_minor = 0, ver_patch = 0;
    1184             :         char dot;
    1185         284 :         iss >> ver_major >> dot >> ver_minor >> dot >> ver_patch;
    1186         284 :         vector_data.set_version(LIBMESH_VERSION_ID(ver_major, ver_minor, ver_patch));
    1187             : 
    1188             :         // Actually read the header data. When we do this, set read_header=false
    1189             :         // so that we do not reinit sys, since we assume that it has already been
    1190             :         // set up properly (e.g. the appropriate variables have already been added).
    1191         284 :         sys.read_header(vector_data, version, /*read_header=*/false, /*read_additional_data=*/false);
    1192         268 :       }
    1193             : 
    1194             :       // Comply with the System::read_serialized_vectors() interface which uses dumb pointers.
    1195          16 :       std::vector<NumericVector<Number> *> vec_in;
    1196        5240 :       for (auto & vec : vectors)
    1197        4956 :         vec_in.push_back(vec.get());
    1198             : 
    1199           8 :       sys.read_serialized_vectors (vector_data, vec_in);
    1200         268 :     }
    1201             : 
    1202             :   // Undo the temporary renumbering
    1203         284 :   sys.get_mesh().fix_broken_node_and_element_numbering();
    1204         268 : }
    1205             : 
    1206      769828 : void RBEvaluation::check_evaluated_thetas_size(const std::vector<Number> * evaluated_thetas) const
    1207             : {
    1208      769828 :   if (rb_theta_expansion && evaluated_thetas)
    1209             :     {
    1210           0 :       auto actual_size = evaluated_thetas->size();
    1211             :       auto expected_size =
    1212           0 :         rb_theta_expansion->get_n_A_terms() +
    1213           0 :         rb_theta_expansion->get_n_F_terms() +
    1214           0 :         rb_theta_expansion->get_total_n_output_terms();
    1215             : 
    1216           0 :       libmesh_error_msg_if(actual_size != expected_size,
    1217             :                            "ERROR: Evaluated thetas vector has size " <<
    1218             :                            actual_size << ", but we expected " <<
    1219             :                            rb_theta_expansion->get_n_A_terms() << " A term(s), " <<
    1220             :                            rb_theta_expansion->get_n_F_terms() << " F term(s), and " <<
    1221             :                            rb_theta_expansion->get_total_n_output_terms() << " output term(s), " <<
    1222             :                            "for a total of " << expected_size << " terms.");
    1223             :     }
    1224      769828 : }
    1225             : 
    1226             : } // namespace libMesh

Generated by: LCOV version 1.14