Real RBEIMEvaluation::rb_solve(unsigned int N) { // Short-circuit if we are using the same parameters and value of N if( (_previous_parameters == get_parameters()) && (_previous_N == N) ) { return _previous_error_bound; } // Otherwise, update _previous parameters, _previous_N _previous_parameters = get_parameters(); _previous_N = N; LOG_SCOPE("rb_solve()", "RBEIMEvaluation"); if(N > get_n_basis_functions()) libmesh_error_msg("ERROR: N cannot be larger than the number of basis functions in rb_solve"); if(N==0) libmesh_error_msg("ERROR: N must be greater than 0 in rb_solve"); // Get the rhs by sampling parametrized_function // at the first N interpolation_points DenseVector<Number> EIM_rhs(N); for(unsigned int i=0; i<N; i++) { EIM_rhs(i) = evaluate_parametrized_function(interpolation_points_var[i], interpolation_points[i], *interpolation_points_elem[i]); } DenseMatrix<Number> interpolation_matrix_N; interpolation_matrix.get_principal_submatrix(N, interpolation_matrix_N); interpolation_matrix_N.lu_solve(EIM_rhs, RB_solution); // Optionally evaluate an a posteriori error bound. The EIM error estimate // recommended in the literature is based on using "next" EIM point, so // we skip this if N == get_n_basis_functions() if(evaluate_RB_error_bound && (N != get_n_basis_functions())) { // Compute the a posteriori error bound // First, sample the parametrized function at x_{N+1} Number g_at_next_x = evaluate_parametrized_function(interpolation_points_var[N], interpolation_points[N], *interpolation_points_elem[N]); // Next, evaluate the EIM approximation at x_{N+1} Number EIM_approx_at_next_x = 0.; for(unsigned int j=0; j<N; j++) { EIM_approx_at_next_x += RB_solution(j) * interpolation_matrix(N,j); } Real error_estimate = std::abs(g_at_next_x - EIM_approx_at_next_x); _previous_error_bound = error_estimate; return error_estimate; } else // Don't evaluate an error bound { _previous_error_bound = -1.; return -1.; } }
void RBEIMConstruction::enrich_RB_space() { START_LOG("enrich_RB_space()", "RBEIMConstruction"); // put solution in _ghosted_meshfunction_vector so we can access it from the mesh function // this allows us to compute EIM_rhs appropriately solution->localize(*_ghosted_meshfunction_vector, this->get_dof_map().get_send_list()); RBEIMEvaluation& eim_eval = libmesh_cast_ref<RBEIMEvaluation&>(get_rb_evaluation()); // If we have at least one basis function we need to use // rb_solve to find the EIM interpolation error, otherwise just use solution as is if(get_rb_evaluation().get_n_basis_functions() > 0) { // get the right-hand side vector for the EIM approximation // by sampling the parametrized function (stored in solution) // at the interpolation points unsigned int RB_size = get_rb_evaluation().get_n_basis_functions(); DenseVector<Number> EIM_rhs(RB_size); for(unsigned int i=0; i<RB_size; i++) { EIM_rhs(i) = evaluate_mesh_function( eim_eval.interpolation_points_var[i], eim_eval.interpolation_points[i] ); } eim_eval.set_parameters( get_parameters() ); eim_eval.rb_solve(EIM_rhs); // Load the "EIM residual" into solution by subtracting // the EIM approximation for(unsigned int i=0; i<get_rb_evaluation().get_n_basis_functions(); i++) { solution->add(-eim_eval.RB_solution(i), get_rb_evaluation().get_basis_function(i)); } } // need to update since context uses current_local_solution update(); // Find the quadrature point at which solution (which now stores // the "EIM residual") has maximum absolute value // by looping over the mesh Point optimal_point; Number optimal_value = 0.; unsigned int optimal_var; // Compute truth representation via projection const MeshBase& mesh = this->get_mesh(); AutoPtr<FEMContext> c = this->build_context(); FEMContext &context = libmesh_cast_ref<FEMContext&>(*c); this->init_context(context); MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { context.pre_fe_reinit(*this, *el); context.elem_fe_reinit(); for(unsigned int var=0; var<n_vars(); var++) { unsigned int n_qpoints = context.element_qrule->n_points(); for(unsigned int qp=0; qp<n_qpoints; qp++) { Number value = context.interior_value(var, qp); if( std::abs(value) > std::abs(optimal_value) ) { optimal_value = value; optimal_point = context.element_fe_var[var]->get_xyz()[qp]; optimal_var = var; } } } } Real global_abs_value = std::abs(optimal_value); unsigned int proc_ID_index; this->comm().maxloc(global_abs_value, proc_ID_index); // Broadcast the optimal point from proc_ID_index this->comm().broadcast(optimal_point, proc_ID_index); // Also broadcast the corresponding optimal_var and optimal_value this->comm().broadcast(optimal_var, proc_ID_index); this->comm().broadcast(optimal_value, proc_ID_index); // Scale the solution solution->scale(1./optimal_value); // Store optimal point in interpolation_points if(!_performing_extra_greedy_step) { eim_eval.interpolation_points.push_back(optimal_point); eim_eval.interpolation_points_var.push_back(optimal_var); NumericVector<Number>* new_bf = NumericVector<Number>::build(this->comm()).release(); new_bf->init (this->n_dofs(), this->n_local_dofs(), false, libMeshEnums::PARALLEL); *new_bf = *solution; get_rb_evaluation().basis_functions.push_back( new_bf ); } else { eim_eval.extra_interpolation_point = optimal_point; eim_eval.extra_interpolation_point_var = optimal_var; } STOP_LOG("enrich_RB_space()", "RBEIMConstruction"); }
Real RBEIMEvaluation::rb_solve(unsigned int N) { // Short-circuit if we are using the same parameters and value of N if( (_previous_parameters == get_parameters()) && (_previous_N == N) ) { return _previous_error_bound; } // Otherwise, update _previous parameters, _previous_N _previous_parameters = get_parameters(); _previous_N = N; START_LOG("rb_solve()", "RBEIMEvaluation"); if(N > get_n_basis_functions()) { libMesh::err << "ERROR: N cannot be larger than the number " << "of basis functions in rb_solve" << std::endl; libmesh_error(); } if(N==0) { libMesh::err << "ERROR: N must be greater than 0 in rb_solve" << std::endl; libmesh_error(); } // Get the rhs by sampling parametrized_function // at the first N interpolation_points DenseVector<Number> EIM_rhs(N); for(unsigned int i=0; i<N; i++) { EIM_rhs(i) = evaluate_parametrized_function(interpolation_points_var[i], interpolation_points[i]); } DenseMatrix<Number> interpolation_matrix_N; interpolation_matrix.get_principal_submatrix(N, interpolation_matrix_N); interpolation_matrix_N.lu_solve(EIM_rhs, RB_solution); // Evaluate an a posteriori error bound if(evaluate_RB_error_bound) { // Compute the a posteriori error bound // First, sample the parametrized function at x_{N+1} Number g_at_next_x; if(N == get_n_basis_functions()) g_at_next_x = evaluate_parametrized_function(extra_interpolation_point_var, extra_interpolation_point); else g_at_next_x = evaluate_parametrized_function(interpolation_points_var[N], interpolation_points[N]); // Next, evaluate the EIM approximation at x_{N+1} Number EIM_approx_at_next_x = 0.; for(unsigned int j=0; j<N; j++) { if(N == get_n_basis_functions()) { EIM_approx_at_next_x += RB_solution(j) * extra_interpolation_matrix_row(j); } else { EIM_approx_at_next_x += RB_solution(j) * interpolation_matrix(N,j); } } Real error_estimate = std::abs(g_at_next_x - EIM_approx_at_next_x); STOP_LOG("rb_solve()", "RBEIMEvaluation"); _previous_error_bound = error_estimate; return error_estimate; } else // Don't evaluate an error bound { STOP_LOG("rb_solve()", "RBEIMEvaluation"); _previous_error_bound = -1.; return -1.; } }