void UNVIO::count_elements (std::istream& in_file) { START_LOG("count_elements()","UNVIO"); if (this->_n_elements != 0) { libMesh::err << "Error: Trying to scan elements twice!" << std::endl; libmesh_error(); } // Simply read the element // dataset for the @e only // purpose to count nodes! std::string data; unsigned int fe_id; while (!in_file.eof()) { // read element label in_file >> data; // end of dataset? if (data == "-1") break; // read fe_id in_file >> fe_id; // Skip related data, // and node number list in_file.ignore (256,'\n'); in_file.ignore (256,'\n'); // For some elements the node numbers // are given more than one record // TET10 or QUAD9 if (fe_id == 118 || fe_id == 300) in_file.ignore (256,'\n'); // HEX20 if (fe_id == 116) { in_file.ignore (256,'\n'); in_file.ignore (256,'\n'); } this->_n_elements++; } if (in_file.eof()) { libMesh::err << "ERROR: File ended before end of element dataset!" << std::endl; libmesh_error(); } if (this->verbose()) libMesh::out << " Elements: " << this->_n_elements << std::endl; STOP_LOG("count_elements()","UNVIO"); }
void JumpErrorEstimator::estimate_error (const System & system, ErrorVector & error_per_cell, const NumericVector<Number> * solution_vector, bool estimate_parent_error) { START_LOG("estimate_error()", "JumpErrorEstimator"); /* Conventions for assigning the direction of the normal: - e & f are global element ids Case (1.) Elements are at the same level, e<f Compute the flux jump on the face and add it as a contribution to error_per_cell[e] and error_per_cell[f] ---------------------- | | | | | f | | | | | e |---> n | | | | | | | ---------------------- Case (2.) The neighbor is at a higher level. Compute the flux jump on e's face and add it as a contribution to error_per_cell[e] and error_per_cell[f] ---------------------- | | | | | | e |---> n | | | | | |-----------| f | | | | | | | | | | | | | ---------------------- */ // The current mesh const MeshBase & mesh = system.get_mesh(); // The number of variables in the system const unsigned int n_vars = system.n_vars(); // The DofMap for this system const DofMap & dof_map = system.get_dof_map(); // Resize the error_per_cell vector to be // the number of elements, initialize it to 0. error_per_cell.resize (mesh.max_elem_id()); std::fill (error_per_cell.begin(), error_per_cell.end(), 0.); // Declare a vector of floats which is as long as // error_per_cell above, and fill with zeros. This vector will be // used to keep track of the number of edges (faces) on each active // element which are either: // 1) an internal edge // 2) an edge on a Neumann boundary for which a boundary condition // function has been specified. // The error estimator can be scaled by the number of flux edges (faces) // which the element actually has to obtain a more uniform measure // of the error. Use floats instead of ints since in case 2 (above) // f gets 1/2 of a flux face contribution from each of his // neighbors std::vector<float> n_flux_faces; if (scale_by_n_flux_faces) n_flux_faces.resize(error_per_cell.size(), 0); // Prepare current_local_solution to localize a non-standard // solution vector if necessary if (solution_vector && solution_vector != system.solution.get()) { NumericVector<Number> * newsol = const_cast<NumericVector<Number> *>(solution_vector); System & sys = const_cast<System &>(system); newsol->swap(*sys.solution); sys.update(); } fine_context.reset(new FEMContext(system)); coarse_context.reset(new FEMContext(system)); // Loop over all the variables we've been requested to find jumps in, to // pre-request for (var=0; var<n_vars; var++) { // Possibly skip this variable if (error_norm.weight(var) == 0.0) continue; // FIXME: Need to generalize this to vector-valued elements. [PB] FEBase * side_fe = libmesh_nullptr; const std::set<unsigned char> & elem_dims = fine_context->elem_dimensions(); for (std::set<unsigned char>::const_iterator dim_it = elem_dims.begin(); dim_it != elem_dims.end(); ++dim_it) { const unsigned char dim = *dim_it; fine_context->get_side_fe( var, side_fe, dim ); libmesh_assert_not_equal_to(side_fe->get_fe_type().family, SCALAR); side_fe->get_xyz(); } } this->init_context(*fine_context); this->init_context(*coarse_context); // Iterate over all the active elements in the mesh // that live on this processor. MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { // e is necessarily an active element on the local processor const Elem * e = *elem_it; const dof_id_type e_id = e->id(); #ifdef LIBMESH_ENABLE_AMR // See if the parent of element e has been examined yet; // if not, we may want to compute the estimator on it const Elem * parent = e->parent(); // We only can compute and only need to compute on // parents with all active children bool compute_on_parent = true; if (!parent || !estimate_parent_error) compute_on_parent = false; else for (unsigned int c=0; c != parent->n_children(); ++c) if (!parent->child(c)->active()) compute_on_parent = false; if (compute_on_parent && !error_per_cell[parent->id()]) { // Compute a projection onto the parent DenseVector<Number> Uparent; FEBase::coarsened_dof_values (*(system.solution), dof_map, parent, Uparent, false); // Loop over the neighbors of the parent for (unsigned int n_p=0; n_p<parent->n_neighbors(); n_p++) { if (parent->neighbor(n_p) != libmesh_nullptr) // parent has a neighbor here { // Find the active neighbors in this direction std::vector<const Elem *> active_neighbors; parent->neighbor(n_p)-> active_family_tree_by_neighbor(active_neighbors, parent); // Compute the flux to each active neighbor for (unsigned int a=0; a != active_neighbors.size(); ++a) { const Elem * f = active_neighbors[a]; // FIXME - what about when f->level < // parent->level()?? if (f->level() >= parent->level()) { fine_context->pre_fe_reinit(system, f); coarse_context->pre_fe_reinit(system, parent); libmesh_assert_equal_to (coarse_context->get_elem_solution().size(), Uparent.size()); coarse_context->get_elem_solution() = Uparent; this->reinit_sides(); // Loop over all significant variables in the system for (var=0; var<n_vars; var++) if (error_norm.weight(var) != 0.0) { this->internal_side_integration(); error_per_cell[fine_context->get_elem().id()] += static_cast<ErrorVectorReal>(fine_error); error_per_cell[coarse_context->get_elem().id()] += static_cast<ErrorVectorReal>(coarse_error); } // Keep track of the number of internal flux // sides found on each element if (scale_by_n_flux_faces) { n_flux_faces[fine_context->get_elem().id()]++; n_flux_faces[coarse_context->get_elem().id()] += this->coarse_n_flux_faces_increment(); } } } } else if (integrate_boundary_sides) { fine_context->pre_fe_reinit(system, parent); libmesh_assert_equal_to (fine_context->get_elem_solution().size(), Uparent.size()); fine_context->get_elem_solution() = Uparent; fine_context->side = n_p; fine_context->side_fe_reinit(); // If we find a boundary flux for any variable, // let's just count it as a flux face for all // variables. Otherwise we'd need to keep track of // a separate n_flux_faces and error_per_cell for // every single var. bool found_boundary_flux = false; for (var=0; var<n_vars; var++) if (error_norm.weight(var) != 0.0) { if (this->boundary_side_integration()) { error_per_cell[fine_context->get_elem().id()] += static_cast<ErrorVectorReal>(fine_error); found_boundary_flux = true; } } if (scale_by_n_flux_faces && found_boundary_flux) n_flux_faces[fine_context->get_elem().id()]++; } } } #endif // #ifdef LIBMESH_ENABLE_AMR // If we do any more flux integration, e will be the fine element fine_context->pre_fe_reinit(system, e); // Loop over the neighbors of element e for (unsigned int n_e=0; n_e<e->n_neighbors(); n_e++) { if ((e->neighbor(n_e) != libmesh_nullptr) || integrate_boundary_sides) { fine_context->side = n_e; fine_context->side_fe_reinit(); } if (e->neighbor(n_e) != libmesh_nullptr) // e is not on the boundary { const Elem * f = e->neighbor(n_e); const dof_id_type f_id = f->id(); // Compute flux jumps if we are in case 1 or case 2. if ((f->active() && (f->level() == e->level()) && (e_id < f_id)) || (f->level() < e->level())) { // f is now the coarse element coarse_context->pre_fe_reinit(system, f); this->reinit_sides(); // Loop over all significant variables in the system for (var=0; var<n_vars; var++) if (error_norm.weight(var) != 0.0) { this->internal_side_integration(); error_per_cell[fine_context->get_elem().id()] += static_cast<ErrorVectorReal>(fine_error); error_per_cell[coarse_context->get_elem().id()] += static_cast<ErrorVectorReal>(coarse_error); } // Keep track of the number of internal flux // sides found on each element if (scale_by_n_flux_faces) { n_flux_faces[fine_context->get_elem().id()]++; n_flux_faces[coarse_context->get_elem().id()] += this->coarse_n_flux_faces_increment(); } } // end if (case1 || case2) } // if (e->neigbor(n_e) != libmesh_nullptr) // Otherwise, e is on the boundary. If it happens to // be on a Dirichlet boundary, we need not do anything. // On the other hand, if e is on a Neumann (flux) boundary // with grad(u).n = g, we need to compute the additional residual // (h * \int |g - grad(u_h).n|^2 dS)^(1/2). // We can only do this with some knowledge of the boundary // conditions, i.e. the user must have attached an appropriate // BC function. else if (integrate_boundary_sides) { bool found_boundary_flux = false; for (var=0; var<n_vars; var++) if (error_norm.weight(var) != 0.0) if (this->boundary_side_integration()) { error_per_cell[fine_context->get_elem().id()] += static_cast<ErrorVectorReal>(fine_error); found_boundary_flux = true; } if (scale_by_n_flux_faces && found_boundary_flux) n_flux_faces[fine_context->get_elem().id()]++; } // end if (e->neighbor(n_e) == libmesh_nullptr) } // end loop over neighbors } // End loop over active local elements // Each processor has now computed the error contribuions // for its local elements. We need to sum the vector // and then take the square-root of each component. Note // that we only need to sum if we are running on multiple // processors, and we only need to take the square-root // if the value is nonzero. There will in general be many // zeros for the inactive elements. // First sum the vector of estimated error values this->reduce_error(error_per_cell, system.comm()); // Compute the square-root of each component. for (std::size_t i=0; i<error_per_cell.size(); i++) if (error_per_cell[i] != 0.) error_per_cell[i] = std::sqrt(error_per_cell[i]); if (this->scale_by_n_flux_faces) { // Sum the vector of flux face counts this->reduce_error(n_flux_faces, system.comm()); // Sanity check: Make sure the number of flux faces is // always an integer value #ifdef DEBUG for (unsigned int i=0; i<n_flux_faces.size(); ++i) libmesh_assert_equal_to (n_flux_faces[i], static_cast<float>(static_cast<unsigned int>(n_flux_faces[i])) ); #endif // Scale the error by the number of flux faces for each element for (unsigned int i=0; i<n_flux_faces.size(); ++i) { if (n_flux_faces[i] == 0.0) // inactive or non-local element continue; //libMesh::out << "Element " << i << " has " << n_flux_faces[i] << " flux faces." << std::endl; error_per_cell[i] /= static_cast<ErrorVectorReal>(n_flux_faces[i]); } } // If we used a non-standard solution before, now is the time to fix // the current_local_solution if (solution_vector && solution_vector != system.solution.get()) { NumericVector<Number> * newsol = const_cast<NumericVector<Number> *>(solution_vector); System & sys = const_cast<System &>(system); newsol->swap(*sys.solution); sys.update(); } STOP_LOG("estimate_error()", "JumpErrorEstimator"); }
Real RBEvaluation::rb_solve(unsigned int N) { START_LOG("rb_solve()", "RBEvaluation"); if(N > get_n_basis_functions()) libmesh_error_msg("ERROR: N cannot be larger than the number of basis functions in rb_solve"); const RBParameters& mu = get_parameters(); // Resize (and clear) the solution vector RB_solution.resize(N); // Assemble the RB system DenseMatrix<Number> RB_system_matrix(N,N); RB_system_matrix.zero(); DenseMatrix<Number> RB_Aq_a; for(unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++) { RB_Aq_vector[q_a].get_principal_submatrix(N, RB_Aq_a); RB_system_matrix.add(rb_theta_expansion->eval_A_theta(q_a, mu), RB_Aq_a); } // Assemble the RB rhs DenseVector<Number> RB_rhs(N); RB_rhs.zero(); DenseVector<Number> RB_Fq_f; for(unsigned int q_f=0; q_f<rb_theta_expansion->get_n_F_terms(); q_f++) { RB_Fq_vector[q_f].get_principal_subvector(N, RB_Fq_f); RB_rhs.add(rb_theta_expansion->eval_F_theta(q_f, mu), RB_Fq_f); } // Solve the linear system if(N > 0) { RB_system_matrix.lu_solve(RB_rhs, RB_solution); } // Evaluate RB outputs DenseVector<Number> RB_output_vector_N; for(unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++) { RB_outputs[n] = 0.; for(unsigned int q_l=0; q_l<rb_theta_expansion->get_n_output_terms(n); q_l++) { RB_output_vectors[n][q_l].get_principal_subvector(N, RB_output_vector_N); RB_outputs[n] += rb_theta_expansion->eval_output_theta(n,q_l,mu)*RB_output_vector_N.dot(RB_solution); } } if(evaluate_RB_error_bound) // Calculate the error bounds { // Evaluate the dual norm of the residual for RB_solution_vector Real epsilon_N = compute_residual_dual_norm(N); // Get lower bound for coercivity constant const Real alpha_LB = get_stability_lower_bound(); // alpha_LB needs to be positive to get a valid error bound libmesh_assert_greater ( alpha_LB, 0. ); // Evaluate the (absolute) error bound Real abs_error_bound = epsilon_N / residual_scaling_denom(alpha_LB); // Now compute the output error bounds for(unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++) { RB_output_error_bounds[n] = abs_error_bound * eval_output_dual_norm(n, mu); } STOP_LOG("rb_solve()", "RBEvaluation"); return abs_error_bound; } else // Don't calculate the error bounds { STOP_LOG("rb_solve()", "RBEvaluation"); // Just return -1. if we did not compute the error bound return -1.; } }
void NloptOptimizationSolver<T>::solve () { START_LOG("solve()", "NloptOptimizationSolver"); this->init (); unsigned int nlopt_size = this->system().solution->size(); // We have to have an objective function libmesh_assert( this->objective_object ); // Set routine for objective and (optionally) gradient evaluation { nlopt_result ierr = nlopt_set_min_objective(_opt, __libmesh_nlopt_objective, this); if (ierr < 0) libmesh_error_msg("NLopt failed to set min objective: " << ierr); } if (this->lower_and_upper_bounds_object) { // Need to actually compute the bounds vectors first this->lower_and_upper_bounds_object->lower_and_upper_bounds(this->system()); std::vector<Real> nlopt_lb(nlopt_size); std::vector<Real> nlopt_ub(nlopt_size); for(unsigned int i=0; i<nlopt_size; i++) { nlopt_lb[i] = this->system().get_vector("lower_bounds")(i); nlopt_ub[i] = this->system().get_vector("upper_bounds")(i); } nlopt_set_lower_bounds(_opt, &nlopt_lb[0]); nlopt_set_upper_bounds(_opt, &nlopt_ub[0]); } // If we have an equality constraints object, tell NLopt about it. if (this->equality_constraints_object) { // NLopt requires a vector to specify the tolerance for each constraint. // NLopt makes a copy of this vector internally, so it's safe for us to // let it go out of scope. std::vector<double> equality_constraints_tolerances(this->system().C_eq->size(), _constraints_tolerance); // It would be nice to call the C interface directly, at least it should return an error // code we could parse... unfortunately, there does not seem to be a way to extract // the underlying nlopt_opt object from the nlopt::opt class! nlopt_result ierr = nlopt_add_equality_mconstraint(_opt, equality_constraints_tolerances.size(), __libmesh_nlopt_equality_constraints, this, &equality_constraints_tolerances[0]); if (ierr < 0) libmesh_error_msg("NLopt failed to add equality constraint: " << ierr); } // If we have an inequality constraints object, tell NLopt about it. if (this->inequality_constraints_object) { // NLopt requires a vector to specify the tolerance for each constraint std::vector<double> inequality_constraints_tolerances(this->system().C_ineq->size(), _constraints_tolerance); nlopt_add_inequality_mconstraint(_opt, inequality_constraints_tolerances.size(), __libmesh_nlopt_inequality_constraints, this, &inequality_constraints_tolerances[0]); } // Set a relative tolerance on the optimization parameters nlopt_set_ftol_rel(_opt, this->objective_function_relative_tolerance); // Set the maximum number of allowed objective function evaluations nlopt_set_maxeval(_opt, this->max_objective_function_evaluations); // Reset internal iteration counter this->_iteration_count = 0; // Perform the optimization std::vector<Real> x(nlopt_size); Real min_val = 0.; _result = nlopt_optimize(_opt, &x[0], &min_val); if (_result < 0) libMesh::out << "NLopt failed!" << std::endl; else libMesh::out << "NLopt obtained optimal value: " << min_val << " in " << this->get_iteration_count() << " iterations." << std::endl; STOP_LOG("solve()", "NloptOptimizationSolver"); }
Real RBEIMConstruction::truth_solve(int plot_solution) { START_LOG("truth_solve()", "RBEIMConstruction"); int training_parameters_found_index = -1; if( _parametrized_functions_in_training_set_initialized ) { // Check if parameters are in the training set. If so, we can just load the // solution from _parametrized_functions_in_training_set for(unsigned int i=0; i<get_n_training_samples(); i++) { if(get_parameters() == get_params_from_training_set(i)) { training_parameters_found_index = i; break; } } } // If the parameters are in the training set, just copy the solution vector if(training_parameters_found_index >= 0) { *solution = *_parametrized_functions_in_training_set[training_parameters_found_index]; update(); // put the solution into current_local_solution as well } // Otherwise, we have to compute the projection else { RBEIMEvaluation& eim_eval = cast_ref<RBEIMEvaluation&>(get_rb_evaluation()); eim_eval.set_parameters( get_parameters() ); // Compute truth representation via projection const MeshBase& mesh = this->get_mesh(); UniquePtr<DGFEMContext> c = this->build_context(); DGFEMContext &context = cast_ref<DGFEMContext&>(*c); this->init_context(context); rhs->zero(); 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(); // All variables should have the same quadrature rule, hence // we can get JxW and xyz based on first_elem_fe. FEBase* first_elem_fe = NULL; context.get_element_fe( 0, first_elem_fe ); unsigned int n_qpoints = context.get_element_qrule().n_points(); const std::vector<Real> &JxW = first_elem_fe->get_JxW(); const std::vector<Point> &xyz = first_elem_fe->get_xyz(); // Loop over qp before var because parametrized functions often use // some caching based on qp. for (unsigned int qp=0; qp<n_qpoints; qp++) { for (unsigned int var=0; var<n_vars(); var++) { FEBase* elem_fe = NULL; context.get_element_fe( var, elem_fe ); const std::vector<std::vector<Real> >& phi = elem_fe->get_phi(); DenseSubVector<Number>& subresidual_var = context.get_elem_residual( var ); unsigned int n_var_dofs = cast_int<unsigned int>(context.get_dof_indices( var ).size()); Number eval_result = eim_eval.evaluate_parametrized_function(var, xyz[qp], *(*el)); for (unsigned int i=0; i != n_var_dofs; i++) subresidual_var(i) += JxW[qp] * eval_result * phi[i][qp]; } } // Apply constraints, e.g. periodic constraints this->get_dof_map().constrain_element_vector(context.get_elem_residual(), context.get_dof_indices() ); // Add element vector to global vector rhs->add_vector(context.get_elem_residual(), context.get_dof_indices() ); } // Solve to find the best fit, then solution stores the truth representation // of the function to be approximated solve_for_matrix_and_rhs(*inner_product_solver, *inner_product_matrix, *rhs); if (assert_convergence) check_convergence(*inner_product_solver); } if(plot_solution > 0) { #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO(get_mesh()).write_equation_systems ("truth.exo", this->get_equation_systems()); #endif } STOP_LOG("truth_solve()", "RBEIMConstruction"); return 0.; }
void RBEIMEvaluation::legacy_read_offline_data_from_files(const std::string& directory_name, bool read_error_bound_data, const bool read_binary_data) { START_LOG("legacy_read_offline_data_from_files()", "RBEIMEvaluation"); Parent::legacy_read_offline_data_from_files(directory_name, read_error_bound_data); // First, find out how many basis functions we had when Greedy terminated // This was set in RBSystem::read_offline_data_from_files unsigned int n_bfs = this->get_n_basis_functions(); // The writing mode: DECODE for binary, READ for ASCII XdrMODE mode = read_binary_data ? DECODE : READ; // The suffix to use for all the files that are written out const std::string suffix = read_binary_data ? ".xdr" : ".dat"; // Stream for creating file names std::ostringstream file_name; // Read in the interpolation matrix file_name.str(""); file_name << directory_name << "/interpolation_matrix" << suffix; assert_file_exists(file_name.str()); Xdr interpolation_matrix_in(file_name.str(), mode); for(unsigned int i=0; i<n_bfs; i++) { for(unsigned int j=0; j<=i; j++) { Number value; interpolation_matrix_in >> value; interpolation_matrix(i,j) = value; } } interpolation_matrix_in.close(); // Also, read in the "extra" row file_name.str(""); file_name << directory_name << "/extra_interpolation_matrix_row" << suffix; assert_file_exists(file_name.str()); Xdr extra_interpolation_matrix_row_in(file_name.str(), mode); for(unsigned int j=0; j<n_bfs; j++) { Number value; extra_interpolation_matrix_row_in >> value; extra_interpolation_matrix_row(j) = value; } extra_interpolation_matrix_row_in.close(); // Next read in interpolation_points file_name.str(""); file_name << directory_name << "/interpolation_points" << suffix; assert_file_exists(file_name.str()); Xdr interpolation_points_in(file_name.str(), mode); for(unsigned int i=0; i<n_bfs; i++) { Real x_val, y_val, z_val = 0.; interpolation_points_in >> x_val; if(LIBMESH_DIM >= 2) interpolation_points_in >> y_val; if(LIBMESH_DIM >= 3) interpolation_points_in >> z_val; Point p(x_val, y_val, z_val); interpolation_points.push_back(p); } interpolation_points_in.close(); // Also, read in the extra interpolation point file_name.str(""); file_name << directory_name << "/extra_interpolation_point" << suffix; assert_file_exists(file_name.str()); Xdr extra_interpolation_point_in(file_name.str(), mode); { Real x_val, y_val, z_val = 0.; extra_interpolation_point_in >> x_val; if(LIBMESH_DIM >= 2) extra_interpolation_point_in >> y_val; if(LIBMESH_DIM >= 3) extra_interpolation_point_in >> z_val; Point p(x_val, y_val, z_val); extra_interpolation_point = p; } extra_interpolation_point_in.close(); // Next read in interpolation_points_var file_name.str(""); file_name << directory_name << "/interpolation_points_var" << suffix; assert_file_exists(file_name.str()); Xdr interpolation_points_var_in(file_name.str(), mode); for(unsigned int i=0; i<n_bfs; i++) { unsigned int var; interpolation_points_var_in >> var; interpolation_points_var.push_back(var); } interpolation_points_var_in.close(); // Also, read in extra_interpolation_point_var file_name.str(""); file_name << directory_name << "/extra_interpolation_point_var" << suffix; assert_file_exists(file_name.str()); Xdr extra_interpolation_point_var_in(file_name.str(), mode); { unsigned int var; extra_interpolation_point_var_in >> var; extra_interpolation_point_var = var; } extra_interpolation_point_var_in.close(); // Read in the elements corresponding to the interpolation points legacy_read_in_interpolation_points_elem(directory_name); STOP_LOG("legacy_read_offline_data_from_files()", "RBEIMEvaluation"); }
void __libmesh_nlopt_inequality_constraints(unsigned m, double * result, unsigned n, const double * x, double * gradient, void * data) { START_LOG("inequality_constraints()", "NloptOptimizationSolver"); libmesh_assert(data); // data should be a pointer to the solver (it was passed in as void *) NloptOptimizationSolver<Number> * solver = static_cast<NloptOptimizationSolver<Number> *> (data); OptimizationSystem & sys = solver->system(); // We'll use current_local_solution below, so let's ensure that it's consistent // with the vector x that was passed in. if (sys.solution->size() != n) libmesh_error_msg("Error: Input vector x has different length than sys.solution!"); for(unsigned int i=sys.solution->first_local_index(); i<sys.solution->last_local_index(); i++) sys.solution->set(i, x[i]); sys.solution->close(); // Impose constraints on the solution vector sys.get_dof_map().enforce_constraints_exactly(sys); // Update sys.current_local_solution based on the solution vector sys.update(); // Call the user's inequality constraints function if there is one. OptimizationSystem::ComputeInequalityConstraints * ineco = solver->inequality_constraints_object; if (ineco) { ineco->inequality_constraints(*sys.current_local_solution, *sys.C_ineq, sys); sys.C_ineq->close(); // Copy the values out of ineq_constraints into 'result'. // TODO: Even better would be if we could use 'result' directly // as the storage of ineq_constraints. Perhaps a serial-only // NumericVector variant which supports this option? for (unsigned i=0; i<m; ++i) result[i] = (*sys.C_ineq)(i); // If gradient != NULL, then the Jacobian matrix of the equality // constraints has been requested. The incoming 'gradient' // array is of length m*n and d(c_i)/d(x_j) = gradient[n*i+j]. if (gradient) { OptimizationSystem::ComputeInequalityConstraintsJacobian * ineco_jac = solver->inequality_constraints_jacobian_object; if (ineco_jac) { ineco_jac->inequality_constraints_jacobian(*sys.current_local_solution, *sys.C_ineq_jac, sys); sys.C_ineq_jac->close(); // copy the Jacobian data to the gradient array for(numeric_index_type i=0; i<m; i++) { std::set<numeric_index_type>::iterator it = sys.ineq_constraint_jac_sparsity[i].begin(); std::set<numeric_index_type>::iterator it_end = sys.ineq_constraint_jac_sparsity[i].end(); for( ; it != it_end; ++it) { numeric_index_type dof_index = *it; gradient[n*i+dof_index] = (*sys.C_ineq_jac)(i,dof_index); } } } else libmesh_error_msg("Jacobian function not defined in __libmesh_nlopt_inequality_constraints"); } } else libmesh_error_msg("Constraints function not defined in __libmesh_nlopt_inequality_constraints"); STOP_LOG("inequality_constraints()", "NloptOptimizationSolver"); }
void InfFE<Dim,T_radial,T_map>::init_shape_functions(const Elem * inf_elem) { libmesh_assert(inf_elem); // Start logging the radial shape function initialization START_LOG("init_shape_functions()", "InfFE"); // ----------------------------------------------------------------- // fast access to some const int's for the radial data const unsigned int n_radial_mapping_sf = cast_int<unsigned int>(radial_map.size()); const unsigned int n_radial_approx_sf = cast_int<unsigned int>(mode.size()); const unsigned int n_radial_qp = cast_int<unsigned int>(som.size()); // ----------------------------------------------------------------- // initialize most of the things related to mapping // The element type and order to use in the base map const Order base_mapping_order ( base_elem->default_order() ); const ElemType base_mapping_elem_type ( base_elem->type() ); // the number of base shape functions used to construct the map // (Lagrange shape functions are used for mapping in the base) unsigned int n_base_mapping_shape_functions = Base::n_base_mapping_sf(base_mapping_elem_type, base_mapping_order); const unsigned int n_total_mapping_shape_functions = n_radial_mapping_sf * n_base_mapping_shape_functions; // ----------------------------------------------------------------- // initialize most of the things related to physical approximation unsigned int n_base_approx_shape_functions; if (Dim > 1) n_base_approx_shape_functions = base_fe->n_shape_functions(); else n_base_approx_shape_functions = 1; const unsigned int n_total_approx_shape_functions = n_radial_approx_sf * n_base_approx_shape_functions; // update class member field _n_total_approx_sf = n_total_approx_shape_functions; // The number of the base quadrature points. const unsigned int n_base_qp = base_qrule->n_points(); // The total number of quadrature points. const unsigned int n_total_qp = n_radial_qp * n_base_qp; // update class member field _n_total_qp = n_total_qp; // ----------------------------------------------------------------- // initialize the node and shape numbering maps { // these vectors work as follows: the i-th entry stores // the associated base/radial node number _radial_node_index.resize (n_total_mapping_shape_functions); _base_node_index.resize (n_total_mapping_shape_functions); // similar for the shapes: the i-th entry stores // the associated base/radial shape number _radial_shape_index.resize (n_total_approx_shape_functions); _base_shape_index.resize (n_total_approx_shape_functions); const ElemType inf_elem_type (inf_elem->type()); // fill the node index map for (unsigned int n=0; n<n_total_mapping_shape_functions; n++) { compute_node_indices (inf_elem_type, n, _base_node_index[n], _radial_node_index[n]); libmesh_assert_less (_base_node_index[n], n_base_mapping_shape_functions); libmesh_assert_less (_radial_node_index[n], n_radial_mapping_sf); } // fill the shape index map for (unsigned int n=0; n<n_total_approx_shape_functions; n++) { compute_shape_indices (this->fe_type, inf_elem_type, n, _base_shape_index[n], _radial_shape_index[n]); libmesh_assert_less (_base_shape_index[n], n_base_approx_shape_functions); libmesh_assert_less (_radial_shape_index[n], n_radial_approx_sf); } } // ----------------------------------------------------------------- // resize the base data fields dist.resize(n_base_mapping_shape_functions); // ----------------------------------------------------------------- // resize the total data fields // the phase term varies with xi, eta and zeta(v): store it for _all_ qp // // when computing the phase, we need the base approximations // therefore, initialize the phase here, but evaluate it // in combine_base_radial(). // // the weight, though, is only needed at the radial quadrature points, n_radial_qp. // but for a uniform interface to the protected data fields // the weight data field (which are accessible from the outside) are expanded to n_total_qp. weight.resize (n_total_qp); dweightdv.resize (n_total_qp); dweight.resize (n_total_qp); dphase.resize (n_total_qp); dphasedxi.resize (n_total_qp); dphasedeta.resize (n_total_qp); dphasedzeta.resize (n_total_qp); // this vector contains the integration weights for the combined quadrature rule _total_qrule_weights.resize(n_total_qp); // ----------------------------------------------------------------- // InfFE's data fields phi, dphi, dphidx, phi_map etc hold the _total_ // shape and mapping functions, respectively { phi.resize (n_total_approx_shape_functions); dphi.resize (n_total_approx_shape_functions); dphidx.resize (n_total_approx_shape_functions); dphidy.resize (n_total_approx_shape_functions); dphidz.resize (n_total_approx_shape_functions); dphidxi.resize (n_total_approx_shape_functions); #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES libmesh_do_once(libMesh::err << "Second derivatives for Infinite elements" << " are not yet implemented!" << std::endl); d2phi.resize (n_total_approx_shape_functions); d2phidx2.resize (n_total_approx_shape_functions); d2phidxdy.resize (n_total_approx_shape_functions); d2phidxdz.resize (n_total_approx_shape_functions); d2phidy2.resize (n_total_approx_shape_functions); d2phidydz.resize (n_total_approx_shape_functions); d2phidz2.resize (n_total_approx_shape_functions); d2phidxi2.resize (n_total_approx_shape_functions); if (Dim > 1) { d2phidxideta.resize (n_total_approx_shape_functions); d2phideta2.resize (n_total_approx_shape_functions); } if (Dim > 2) { d2phidetadzeta.resize (n_total_approx_shape_functions); d2phidxidzeta.resize (n_total_approx_shape_functions); d2phidzeta2.resize (n_total_approx_shape_functions); } #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES if (Dim > 1) dphideta.resize (n_total_approx_shape_functions); if (Dim == 3) dphidzeta.resize (n_total_approx_shape_functions); std::vector<std::vector<Real> > & phi_map = this->_fe_map->get_phi_map(); std::vector<std::vector<Real> > & dphidxi_map = this->_fe_map->get_dphidxi_map(); phi_map.resize (n_total_mapping_shape_functions); dphidxi_map.resize (n_total_mapping_shape_functions); #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES std::vector<std::vector<Real> > & d2phidxi2_map = this->_fe_map->get_d2phidxi2_map(); d2phidxi2_map.resize (n_total_mapping_shape_functions); if (Dim > 1) { std::vector<std::vector<Real> > & d2phidxideta_map = this->_fe_map->get_d2phidxideta_map(); std::vector<std::vector<Real> > & d2phideta2_map = this->_fe_map->get_d2phideta2_map(); d2phidxideta_map.resize (n_total_mapping_shape_functions); d2phideta2_map.resize (n_total_mapping_shape_functions); } if (Dim == 3) { std::vector<std::vector<Real> > & d2phidxidzeta_map = this->_fe_map->get_d2phidxidzeta_map(); std::vector<std::vector<Real> > & d2phidetadzeta_map = this->_fe_map->get_d2phidetadzeta_map(); std::vector<std::vector<Real> > & d2phidzeta2_map = this->_fe_map->get_d2phidzeta2_map(); d2phidxidzeta_map.resize (n_total_mapping_shape_functions); d2phidetadzeta_map.resize (n_total_mapping_shape_functions); d2phidzeta2_map.resize (n_total_mapping_shape_functions); } #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES if (Dim > 1) { std::vector<std::vector<Real> > & dphideta_map = this->_fe_map->get_dphideta_map(); dphideta_map.resize (n_total_mapping_shape_functions); } if (Dim == 3) { std::vector<std::vector<Real> > & dphidzeta_map = this->_fe_map->get_dphidzeta_map(); dphidzeta_map.resize (n_total_mapping_shape_functions); } } // ----------------------------------------------------------------- // collect all the for loops, where inner vectors are // resized to the appropriate number of quadrature points { for (unsigned int i=0; i<n_total_approx_shape_functions; i++) { phi[i].resize (n_total_qp); dphi[i].resize (n_total_qp); dphidx[i].resize (n_total_qp); dphidy[i].resize (n_total_qp); dphidz[i].resize (n_total_qp); dphidxi[i].resize (n_total_qp); #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES d2phi[i].resize (n_total_qp); d2phidx2[i].resize (n_total_qp); d2phidxdy[i].resize (n_total_qp); d2phidxdz[i].resize (n_total_qp); d2phidy2[i].resize (n_total_qp); d2phidydz[i].resize (n_total_qp); d2phidy2[i].resize (n_total_qp); d2phidxi2[i].resize (n_total_qp); if (Dim > 1) { d2phidxideta[i].resize (n_total_qp); d2phideta2[i].resize (n_total_qp); } if (Dim > 2) { d2phidxidzeta[i].resize (n_total_qp); d2phidetadzeta[i].resize (n_total_qp); d2phidzeta2[i].resize (n_total_qp); } #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES if (Dim > 1) dphideta[i].resize (n_total_qp); if (Dim == 3) dphidzeta[i].resize (n_total_qp); } for (unsigned int i=0; i<n_total_mapping_shape_functions; i++) { std::vector<std::vector<Real> > & phi_map = this->_fe_map->get_phi_map(); std::vector<std::vector<Real> > & dphidxi_map = this->_fe_map->get_dphidxi_map(); phi_map[i].resize (n_total_qp); dphidxi_map[i].resize (n_total_qp); #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES std::vector<std::vector<Real> > & d2phidxi2_map = this->_fe_map->get_d2phidxi2_map(); d2phidxi2_map[i].resize (n_total_qp); if (Dim > 1) { std::vector<std::vector<Real> > & d2phidxideta_map = this->_fe_map->get_d2phidxideta_map(); std::vector<std::vector<Real> > & d2phideta2_map = this->_fe_map->get_d2phideta2_map(); d2phidxideta_map[i].resize (n_total_qp); d2phideta2_map[i].resize (n_total_qp); } if (Dim > 2) { std::vector<std::vector<Real> > & d2phidxidzeta_map = this->_fe_map->get_d2phidxidzeta_map(); std::vector<std::vector<Real> > & d2phidetadzeta_map = this->_fe_map->get_d2phidetadzeta_map(); std::vector<std::vector<Real> > & d2phidzeta2_map = this->_fe_map->get_d2phidzeta2_map(); d2phidxidzeta_map[i].resize (n_total_qp); d2phidetadzeta_map[i].resize (n_total_qp); d2phidzeta2_map[i].resize (n_total_qp); } #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES if (Dim > 1) { std::vector<std::vector<Real> > & dphideta_map = this->_fe_map->get_dphideta_map(); dphideta_map[i].resize (n_total_qp); } if (Dim == 3) { std::vector<std::vector<Real> > & dphidzeta_map = this->_fe_map->get_dphidzeta_map(); dphidzeta_map[i].resize (n_total_qp); } } } { // ----------------------------------------------------------------- // (a) compute scalar values at _all_ quadrature points -- for uniform // access from the outside to these fields // (b) form a std::vector<Real> which contains the appropriate weights // of the combined quadrature rule! const std::vector<Point> & radial_qp = radial_qrule->get_points(); libmesh_assert_equal_to (radial_qp.size(), n_radial_qp); const std::vector<Real> & radial_qw = radial_qrule->get_weights(); const std::vector<Real> & base_qw = base_qrule->get_weights(); libmesh_assert_equal_to (radial_qw.size(), n_radial_qp); libmesh_assert_equal_to (base_qw.size(), n_base_qp); for (unsigned int rp=0; rp<n_radial_qp; rp++) for (unsigned int bp=0; bp<n_base_qp; bp++) { weight [ bp+rp*n_base_qp ] = Radial::D (radial_qp[rp](0)); dweightdv[ bp+rp*n_base_qp ] = Radial::D_deriv (radial_qp[rp](0)); _total_qrule_weights[ bp+rp*n_base_qp ] = radial_qw[rp] * base_qw[bp]; } } /** * Stop logging the radial shape function initialization */ STOP_LOG("init_shape_functions()", "InfFE"); }
void InfFE<Dim,T_radial,T_map>::combine_base_radial(const Elem * inf_elem) { libmesh_assert(inf_elem); // at least check whether the base element type is correct. // otherwise this version of computing dist would give problems libmesh_assert_equal_to (base_elem->type(), Base::get_elem_type(inf_elem->type())); /** * Start logging the combination of radial and base parts */ START_LOG("combine_base_radial()", "InfFE"); // zero the phase, since it is to be summed up std::fill (dphasedxi.begin(), dphasedxi.end(), 0.); std::fill (dphasedeta.begin(), dphasedeta.end(), 0.); std::fill (dphasedzeta.begin(), dphasedzeta.end(), 0.); const unsigned int n_base_mapping_sf = cast_int<unsigned int>(dist.size()); const Point origin = inf_elem->origin(); // for each new infinite element, compute the radial distances for (unsigned int n=0; n<n_base_mapping_sf; n++) dist[n] = Point(base_elem->point(n) - origin).size(); switch (Dim) { //------------------------------------------------------------ // 1D case 1: { libmesh_not_implemented(); break; } //------------------------------------------------------------ // 2D case 2: { libmesh_not_implemented(); break; } //------------------------------------------------------------ // 3D case 3: { // fast access to the approximation and mapping shapes of base_fe const std::vector<std::vector<Real> > & S = base_fe->phi; const std::vector<std::vector<Real> > & Ss = base_fe->dphidxi; const std::vector<std::vector<Real> > & St = base_fe->dphideta; const std::vector<std::vector<Real> > & S_map = (base_fe->get_fe_map()).get_phi_map(); const std::vector<std::vector<Real> > & Ss_map = (base_fe->get_fe_map()).get_dphidxi_map(); const std::vector<std::vector<Real> > & St_map = (base_fe->get_fe_map()).get_dphideta_map(); const unsigned int n_radial_qp = radial_qrule->n_points(); const unsigned int n_base_qp = base_qrule-> n_points(); const unsigned int n_total_mapping_sf = cast_int<unsigned int>(radial_map.size()) * n_base_mapping_sf; const unsigned int n_total_approx_sf = Radial::n_dofs(fe_type.radial_order) * base_fe->n_shape_functions(); // compute the phase term derivatives { unsigned int tp=0; for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qp's for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qp's { // sum over all base shapes, to get the average distance for (unsigned int i=0; i<n_base_mapping_sf; i++) { dphasedxi[tp] += Ss_map[i][bp] * dist[i] * radial_map [1][rp]; dphasedeta[tp] += St_map[i][bp] * dist[i] * radial_map [1][rp]; dphasedzeta[tp] += S_map [i][bp] * dist[i] * dradialdv_map[1][rp]; } tp++; } // loop radial and base qp's } libmesh_assert_equal_to (phi.size(), n_total_approx_sf); libmesh_assert_equal_to (dphidxi.size(), n_total_approx_sf); libmesh_assert_equal_to (dphideta.size(), n_total_approx_sf); libmesh_assert_equal_to (dphidzeta.size(), n_total_approx_sf); // compute the overall approximation shape functions, // pick the appropriate radial and base shapes through using // _base_shape_index and _radial_shape_index for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qp's for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qp's for (unsigned int ti=0; ti<n_total_approx_sf; ti++) // over _all_ approx_sf { // let the index vectors take care of selecting the appropriate base/radial shape const unsigned int bi = _base_shape_index [ti]; const unsigned int ri = _radial_shape_index[ti]; phi [ti][bp+rp*n_base_qp] = S [bi][bp] * mode[ri][rp] * som[rp]; dphidxi [ti][bp+rp*n_base_qp] = Ss[bi][bp] * mode[ri][rp] * som[rp]; dphideta [ti][bp+rp*n_base_qp] = St[bi][bp] * mode[ri][rp] * som[rp]; dphidzeta[ti][bp+rp*n_base_qp] = S [bi][bp] * (dmodedv[ri][rp] * som[rp] + mode[ri][rp] * dsomdv[rp]); } std::vector<std::vector<Real> > & phi_map = this->_fe_map->get_phi_map(); std::vector<std::vector<Real> > & dphidxi_map = this->_fe_map->get_dphidxi_map(); std::vector<std::vector<Real> > & dphideta_map = this->_fe_map->get_dphideta_map(); std::vector<std::vector<Real> > & dphidzeta_map = this->_fe_map->get_dphidzeta_map(); libmesh_assert_equal_to (phi_map.size(), n_total_mapping_sf); libmesh_assert_equal_to (dphidxi_map.size(), n_total_mapping_sf); libmesh_assert_equal_to (dphideta_map.size(), n_total_mapping_sf); libmesh_assert_equal_to (dphidzeta_map.size(), n_total_mapping_sf); // compute the overall mapping functions, // pick the appropriate radial and base entries through using // _base_node_index and _radial_node_index for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qp's for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qp's for (unsigned int ti=0; ti<n_total_mapping_sf; ti++) // over all mapping shapes { // let the index vectors take care of selecting the appropriate base/radial mapping shape const unsigned int bi = _base_node_index [ti]; const unsigned int ri = _radial_node_index[ti]; phi_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * radial_map [ri][rp]; dphidxi_map [ti][bp+rp*n_base_qp] = Ss_map[bi][bp] * radial_map [ri][rp]; dphideta_map [ti][bp+rp*n_base_qp] = St_map[bi][bp] * radial_map [ri][rp]; dphidzeta_map[ti][bp+rp*n_base_qp] = S_map [bi][bp] * dradialdv_map[ri][rp]; } break; } default: libmesh_error_msg("Unsupported Dim = " << Dim); } /** * Start logging the combination of radial and base parts */ STOP_LOG("combine_base_radial()", "InfFE"); }
void FEMap::compute_edge_map(int dim, const std::vector<Real>& qw, const Elem* edge) { libmesh_assert (edge != NULL); if (dim == 2) { // A 2D finite element living in either 2D or 3D space. // The edges here are the sides of the element, so the // (misnamed) compute_face_map function does what we want this->compute_face_map(dim, qw, edge); return; } libmesh_assert (dim == 3); // 1D is unnecessary and currently unsupported START_LOG("compute_edge_map()", "FEMap"); // The number of quadrature points. const unsigned int n_qp = qw.size(); // Resize the vectors to hold data at the quadrature points this->xyz.resize(n_qp); this->dxyzdxi_map.resize(n_qp); this->dxyzdeta_map.resize(n_qp); this->d2xyzdxi2_map.resize(n_qp); this->d2xyzdxideta_map.resize(n_qp); this->d2xyzdeta2_map.resize(n_qp); this->tangents.resize(n_qp); this->normals.resize(n_qp); this->curvatures.resize(n_qp); this->JxW.resize(n_qp); // Clear the entities that will be summed for (unsigned int p=0; p<n_qp; p++) { this->tangents[p].resize(1); this->xyz[p].zero(); this->dxyzdxi_map[p].zero(); this->dxyzdeta_map[p].zero(); this->d2xyzdxi2_map[p].zero(); this->d2xyzdxideta_map[p].zero(); this->d2xyzdeta2_map[p].zero(); } // compute x, dxdxi at the quadrature points for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes { const Point& edge_point = edge->point(i); for (unsigned int p=0; p<n_qp; p++) // for each quadrature point... { this->xyz[p].add_scaled (edge_point, this->psi_map[i][p]); this->dxyzdxi_map[p].add_scaled (edge_point, this->dpsidxi_map[i][p]); this->d2xyzdxi2_map[p].add_scaled (edge_point, this->d2psidxi2_map[i][p]); } } // Compute the tangents at the quadrature point // FIXME: normals (plural!) and curvatures are uncalculated for (unsigned int p=0; p<n_qp; p++) { const Point n = this->dxyzdxi_map[p].cross(this->dxyzdeta_map[p]); this->tangents[p][0] = this->dxyzdxi_map[p].unit(); // compute the jacobian at the quadrature points const Real jac = std::sqrt(this->dxdxi_map(p)*this->dxdxi_map(p) + this->dydxi_map(p)*this->dydxi_map(p) + this->dzdxi_map(p)*this->dzdxi_map(p)); libmesh_assert (jac > 0.); this->JxW[p] = jac*qw[p]; } STOP_LOG("compute_edge_map()", "FEMap"); }
void InfFE<Dim,T_radial,T_map>::init_radial_shape_functions(const Elem * libmesh_dbg_var(inf_elem)) { libmesh_assert(radial_qrule); libmesh_assert(inf_elem); /** * Start logging the radial shape function initialization */ START_LOG("init_radial_shape_functions()", "InfFE"); // ----------------------------------------------------------------- // initialize most of the things related to mapping // The order to use in the radial map (currently independent of the element type) const Order radial_mapping_order (Radial::mapping_order()); const unsigned int n_radial_mapping_shape_functions (Radial::n_dofs(radial_mapping_order)); // ----------------------------------------------------------------- // initialize most of the things related to physical approximation const Order radial_approx_order (fe_type.radial_order); const unsigned int n_radial_approx_shape_functions (Radial::n_dofs(radial_approx_order)); const unsigned int n_radial_qp = radial_qrule->n_points(); const std::vector<Point> & radial_qp = radial_qrule->get_points(); // ----------------------------------------------------------------- // resize the radial data fields mode.resize (n_radial_approx_shape_functions); // the radial polynomials (eval) dmodedv.resize (n_radial_approx_shape_functions); som.resize (n_radial_qp); // the (1-v)/2 weight dsomdv.resize (n_radial_qp); radial_map.resize (n_radial_mapping_shape_functions); // the radial map dradialdv_map.resize (n_radial_mapping_shape_functions); for (unsigned int i=0; i<n_radial_mapping_shape_functions; i++) { radial_map[i].resize (n_radial_qp); dradialdv_map[i].resize (n_radial_qp); } for (unsigned int i=0; i<n_radial_approx_shape_functions; i++) { mode[i].resize (n_radial_qp); dmodedv[i].resize (n_radial_qp); } // compute scalar values at radial quadrature points for (unsigned int p=0; p<n_radial_qp; p++) { som[p] = Radial::decay (radial_qp[p](0)); dsomdv[p] = Radial::decay_deriv (radial_qp[p](0)); } // evaluate the mode shapes in radial direction at radial quadrature points for (unsigned int i=0; i<n_radial_approx_shape_functions; i++) for (unsigned int p=0; p<n_radial_qp; p++) { mode[i][p] = InfFE<Dim,T_radial,T_map>::eval (radial_qp[p](0), radial_approx_order, i); dmodedv[i][p] = InfFE<Dim,T_radial,T_map>::eval_deriv (radial_qp[p](0), radial_approx_order, i); } // evaluate the mapping functions in radial direction at radial quadrature points for (unsigned int i=0; i<n_radial_mapping_shape_functions; i++) for (unsigned int p=0; p<n_radial_qp; p++) { radial_map[i][p] = InfFE<Dim,INFINITE_MAP,T_map>::eval (radial_qp[p](0), radial_mapping_order, i); dradialdv_map[i][p] = InfFE<Dim,INFINITE_MAP,T_map>::eval_deriv (radial_qp[p](0), radial_mapping_order, i); } /** * Stop logging the radial shape function initialization */ STOP_LOG("init_radial_shape_functions()", "InfFE"); }
void FEMap::compute_face_map(int dim, const std::vector<Real>& qw, const Elem* side) { libmesh_assert (side != NULL); START_LOG("compute_face_map()", "FEMap"); // The number of quadrature points. const unsigned int n_qp = qw.size(); switch (dim) { case 1: { // A 1D finite element, currently assumed to be in 1D space // This means the boundary is a "0D finite element", a // NODEELEM. // Resize the vectors to hold data at the quadrature points { this->xyz.resize(n_qp); normals.resize(n_qp); this->JxW.resize(n_qp); } // If we have no quadrature points, there's nothing else to do if (!n_qp) break; // We need to look back at the full edge to figure out the normal // vector const Elem *elem = side->parent(); libmesh_assert (elem); if (side->node(0) == elem->node(0)) normals[0] = Point(-1.); else { libmesh_assert (side->node(0) == elem->node(1)); normals[0] = Point(1.); } // Calculate x at the point libmesh_assert (this->psi_map.size() == 1); // In the unlikely event we have multiple quadrature // points, they'll be in the same place for (unsigned int p=0; p<n_qp; p++) { this->xyz[p].zero(); this->xyz[p].add_scaled (side->point(0), this->psi_map[0][p]); normals[p] = normals[0]; this->JxW[p] = 1.0*qw[p]; } // done computing the map break; } case 2: { // A 2D finite element living in either 2D or 3D space. // This means the boundary is a 1D finite element, i.e. // and EDGE2 or EDGE3. // Resize the vectors to hold data at the quadrature points { this->xyz.resize(n_qp); this->dxyzdxi_map.resize(n_qp); this->d2xyzdxi2_map.resize(n_qp); this->tangents.resize(n_qp); this->normals.resize(n_qp); this->curvatures.resize(n_qp); this->JxW.resize(n_qp); } // Clear the entities that will be summed // Compute the tangent & normal at the quadrature point for (unsigned int p=0; p<n_qp; p++) { this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D this->xyz[p].zero(); this->dxyzdxi_map[p].zero(); this->d2xyzdxi2_map[p].zero(); } // compute x, dxdxi at the quadrature points for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes { const Point& side_point = side->point(i); for (unsigned int p=0; p<n_qp; p++) // for each quadrature point... { this->xyz[p].add_scaled (side_point, this->psi_map[i][p]); this->dxyzdxi_map[p].add_scaled (side_point, this->dpsidxi_map[i][p]); this->d2xyzdxi2_map[p].add_scaled(side_point, this->d2psidxi2_map[i][p]); } } // Compute the tangent & normal at the quadrature point for (unsigned int p=0; p<n_qp; p++) { // The first tangent comes from just the edge's Jacobian this->tangents[p][0] = this->dxyzdxi_map[p].unit(); #if LIBMESH_DIM == 2 // For a 2D element living in 2D, the normal is given directly // from the entries in the edge Jacobian. this->normals[p] = (Point(this->dxyzdxi_map[p](1), -this->dxyzdxi_map[p](0), 0.)).unit(); #elif LIBMESH_DIM == 3 // For a 2D element living in 3D, there is a second tangent. // For the second tangent, we need to refer to the full // element's (not just the edge's) Jacobian. const Elem *elem = side->parent(); libmesh_assert (elem != NULL); // Inverse map xyz[p] to a reference point on the parent... Point reference_point = FE<2,LAGRANGE>::inverse_map(elem, this->xyz[p]); // Get dxyz/dxi and dxyz/deta from the parent map. Point dx_dxi = FE<2,LAGRANGE>::map_xi (elem, reference_point); Point dx_deta = FE<2,LAGRANGE>::map_eta(elem, reference_point); // The second tangent vector is formed by crossing these vectors. tangents[p][1] = dx_dxi.cross(dx_deta).unit(); // Finally, the normal in this case is given by crossing these // two tangents. normals[p] = tangents[p][0].cross(tangents[p][1]).unit(); #endif // The curvature is computed via the familiar Frenet formula: // curvature = [d^2(x) / d (xi)^2] dot [normal] // For a reference, see: // F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill, p. 310 // // Note: The sign convention here is different from the // 3D case. Concave-upward curves (smiles) have a positive // curvature. Concave-downward curves (frowns) have a // negative curvature. Be sure to take that into account! const Real numerator = this->d2xyzdxi2_map[p] * this->normals[p]; const Real denominator = this->dxyzdxi_map[p].size_sq(); libmesh_assert (denominator != 0); curvatures[p] = numerator / denominator; } // compute the jacobian at the quadrature points for (unsigned int p=0; p<n_qp; p++) { const Real jac = this->dxyzdxi_map[p].size(); libmesh_assert (jac > 0.); this->JxW[p] = jac*qw[p]; } // done computing the map break; } case 3: { // A 3D finite element living in 3D space. // Resize the vectors to hold data at the quadrature points { this->xyz.resize(n_qp); this->dxyzdxi_map.resize(n_qp); this->dxyzdeta_map.resize(n_qp); this->d2xyzdxi2_map.resize(n_qp); this->d2xyzdxideta_map.resize(n_qp); this->d2xyzdeta2_map.resize(n_qp); this->tangents.resize(n_qp); this->normals.resize(n_qp); this->curvatures.resize(n_qp); this->JxW.resize(n_qp); } // Clear the entities that will be summed for (unsigned int p=0; p<n_qp; p++) { this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D this->xyz[p].zero(); this->dxyzdxi_map[p].zero(); this->dxyzdeta_map[p].zero(); this->d2xyzdxi2_map[p].zero(); this->d2xyzdxideta_map[p].zero(); this->d2xyzdeta2_map[p].zero(); } // compute x, dxdxi at the quadrature points for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes { const Point& side_point = side->point(i); for (unsigned int p=0; p<n_qp; p++) // for each quadrature point... { this->xyz[p].add_scaled (side_point, this->psi_map[i][p]); this->dxyzdxi_map[p].add_scaled (side_point, this->dpsidxi_map[i][p]); this->dxyzdeta_map[p].add_scaled(side_point, this->dpsideta_map[i][p]); this->d2xyzdxi2_map[p].add_scaled (side_point, this->d2psidxi2_map[i][p]); this->d2xyzdxideta_map[p].add_scaled(side_point, this->d2psidxideta_map[i][p]); this->d2xyzdeta2_map[p].add_scaled (side_point, this->d2psideta2_map[i][p]); } } // Compute the tangents, normal, and curvature at the quadrature point for (unsigned int p=0; p<n_qp; p++) { const Point n = this->dxyzdxi_map[p].cross(this->dxyzdeta_map[p]); this->normals[p] = n.unit(); this->tangents[p][0] = this->dxyzdxi_map[p].unit(); this->tangents[p][1] = n.cross(this->dxyzdxi_map[p]).unit(); // Compute curvature using the typical nomenclature // of the first and second fundamental forms. // For reference, see: // 1) http://mathworld.wolfram.com/MeanCurvature.html // (note -- they are using inward normal) // 2) F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill const Real L = -this->d2xyzdxi2_map[p] * this->normals[p]; const Real M = -this->d2xyzdxideta_map[p] * this->normals[p]; const Real N = -this->d2xyzdeta2_map[p] * this->normals[p]; const Real E = this->dxyzdxi_map[p].size_sq(); const Real F = this->dxyzdxi_map[p] * this->dxyzdeta_map[p]; const Real G = this->dxyzdeta_map[p].size_sq(); const Real numerator = E*N -2.*F*M + G*L; const Real denominator = E*G - F*F; libmesh_assert (denominator != 0.); curvatures[p] = 0.5*numerator/denominator; } // compute the jacobian at the quadrature points, see // http://sp81.msi.umn.edu:999/fluent/fidap/help/theory/thtoc.htm for (unsigned int p=0; p<n_qp; p++) { const Real g11 = (dxdxi_map(p)*dxdxi_map(p) + dydxi_map(p)*dydxi_map(p) + dzdxi_map(p)*dzdxi_map(p)); const Real g12 = (dxdxi_map(p)*dxdeta_map(p) + dydxi_map(p)*dydeta_map(p) + dzdxi_map(p)*dzdeta_map(p)); const Real g21 = g12; const Real g22 = (dxdeta_map(p)*dxdeta_map(p) + dydeta_map(p)*dydeta_map(p) + dzdeta_map(p)*dzdeta_map(p)); const Real jac = std::sqrt(g11*g22 - g12*g21); libmesh_assert (jac > 0.); this->JxW[p] = jac*qw[p]; } // done computing the map break; } default: libmesh_error(); } STOP_LOG("compute_face_map()", "FEMap"); }
void FEMap::init_face_shape_functions(const std::vector<Point>& qp, const Elem* side) { libmesh_assert (side != NULL); /** * Start logging the shape function initialization */ START_LOG("init_face_shape_functions()", "FEMap"); // The element type and order to use in // the map const Order mapping_order (side->default_order()); const ElemType mapping_elem_type (side->type()); // The number of quadrature points. const unsigned int n_qp = qp.size(); const unsigned int n_mapping_shape_functions = FE<Dim,LAGRANGE>::n_shape_functions (mapping_elem_type, mapping_order); // resize the vectors to hold current data // Psi are the shape functions used for the FE mapping this->psi_map.resize (n_mapping_shape_functions); if (Dim > 1) { this->dpsidxi_map.resize (n_mapping_shape_functions); this->d2psidxi2_map.resize (n_mapping_shape_functions); } if (Dim == 3) { this->dpsideta_map.resize (n_mapping_shape_functions); this->d2psidxideta_map.resize (n_mapping_shape_functions); this->d2psideta2_map.resize (n_mapping_shape_functions); } for (unsigned int i=0; i<n_mapping_shape_functions; i++) { // Allocate space to store the values of the shape functions // and their first and second derivatives at the quadrature points. this->psi_map[i].resize (n_qp); if (Dim > 1) { this->dpsidxi_map[i].resize (n_qp); this->d2psidxi2_map[i].resize (n_qp); } if (Dim == 3) { this->dpsideta_map[i].resize (n_qp); this->d2psidxideta_map[i].resize (n_qp); this->d2psideta2_map[i].resize (n_qp); } // Compute the value of shape function i, and its first and // second derivatives at quadrature point p // (Lagrange shape functions are used for the mapping) for (unsigned int p=0; p<n_qp; p++) { this->psi_map[i][p] = FE<Dim-1,LAGRANGE>::shape (mapping_elem_type, mapping_order, i, qp[p]); if (Dim > 1) { this->dpsidxi_map[i][p] = FE<Dim-1,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 0, qp[p]); this->d2psidxi2_map[i][p] = FE<Dim-1,LAGRANGE>::shape_second_deriv(mapping_elem_type, mapping_order, i, 0, qp[p]); } // libMesh::out << "this->d2psidxi2_map["<<i<<"][p]=" << d2psidxi2_map[i][p] << std::endl; // If we are in 3D, then our sides are 2D faces. // For the second derivatives, we must also compute the cross // derivative d^2() / dxi deta if (Dim == 3) { this->dpsideta_map[i][p] = FE<Dim-1,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 1, qp[p]); this->d2psidxideta_map[i][p] = FE<Dim-1,LAGRANGE>::shape_second_deriv(mapping_elem_type, mapping_order, i, 1, qp[p]); this->d2psideta2_map[i][p] = FE<Dim-1,LAGRANGE>::shape_second_deriv(mapping_elem_type, mapping_order, i, 2, qp[p]); } } } /** * Stop logging the shape function initialization */ STOP_LOG("init_face_shape_functions()", "FEMap"); }
void UNVIO::node_in (std::istream& in_file) { START_LOG("node_in()","UNVIO"); if (this->verbose()) libMesh::out << " Reading nodes" << std::endl; // adjust the \p istream to our position const bool ok = this->beginning_of_dataset(in_file, _label_dataset_nodes); if (!ok) { libMesh::err << "ERROR: Could not find node dataset!" << std::endl; libmesh_error(); } MeshBase& mesh = MeshInput<MeshBase>::mesh(); unsigned int node_lab; // label of the node unsigned int exp_coord_sys_num, // export coordinate system number (not supported yet) disp_coord_sys_num, // displacement coordinate system number (not supported yet) color; // color (not supported yet) // allocate the correct amount // of memory for the node vector this->_assign_nodes.reserve (this->_n_nodes); // always 3 coordinates in the UNV file, no matter // which dimensionality libMesh is in //std::vector<Real> xyz (3); Point xyz; // depending on whether we have to convert each // coordinate (float), we offer two versions. // Note that \p count_nodes() already verified // whether this file uses "D" of "e" if (this->_need_D_to_e) { // ok, convert... std::string num_buf; for(unsigned int i=0; i<this->_n_nodes; i++) { libmesh_assert (!in_file.eof()); in_file >> node_lab // read the node label >> exp_coord_sys_num // (not supported yet) >> disp_coord_sys_num // (not supported yet) >> color; // (not supported yet) // take care of the // floating-point data for (unsigned int d=0; d<3; d++) { in_file >> num_buf; xyz(d) = this->D_to_e (num_buf); } // set up the id map this->_assign_nodes.push_back (node_lab); // add node to the Mesh & // tell the MeshData object the foreign node id // (note that mesh.add_point() returns a pointer to the new node) this->_mesh_data.add_foreign_node_id (mesh.add_point(xyz,i), node_lab); } }
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_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); // 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, *extra_interpolation_point_elem); else 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++) { 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.; } }
void InfFE<Dim,T_radial,T_map>::compute_shape_functions(const Elem *, const std::vector<Point> &) { libmesh_assert(radial_qrule); // Start logging the overall computation of shape functions START_LOG("compute_shape_functions()", "InfFE"); const unsigned int n_total_qp = _n_total_qp; //------------------------------------------------------------------------- // Compute the shape function values (and derivatives) // at the Quadrature points. Note that the actual values // have already been computed via init_shape_functions // Compute the value of the derivative shape function i at quadrature point p switch (dim) { case 1: { libmesh_not_implemented(); break; } case 2: { libmesh_not_implemented(); break; } case 3: { const std::vector<Real> & dxidx_map = this->_fe_map->get_dxidx(); const std::vector<Real> & dxidy_map = this->_fe_map->get_dxidy(); const std::vector<Real> & dxidz_map = this->_fe_map->get_dxidz(); const std::vector<Real> & detadx_map = this->_fe_map->get_detadx(); const std::vector<Real> & detady_map = this->_fe_map->get_detady(); const std::vector<Real> & detadz_map = this->_fe_map->get_detadz(); const std::vector<Real> & dzetadx_map = this->_fe_map->get_dzetadx(); const std::vector<Real> & dzetady_map = this->_fe_map->get_dzetady(); const std::vector<Real> & dzetadz_map = this->_fe_map->get_dzetadz(); // These are _all_ shape functions of this infinite element for (unsigned int i=0; i<phi.size(); i++) for (unsigned int p=0; p<n_total_qp; p++) { // dphi/dx = (dphi/dxi)*(dxi/dx) + (dphi/deta)*(deta/dx) + (dphi/dzeta)*(dzeta/dx); dphi[i][p](0) = dphidx[i][p] = (dphidxi[i][p]*dxidx_map[p] + dphideta[i][p]*detadx_map[p] + dphidzeta[i][p]*dzetadx_map[p]); // dphi/dy = (dphi/dxi)*(dxi/dy) + (dphi/deta)*(deta/dy) + (dphi/dzeta)*(dzeta/dy); dphi[i][p](1) = dphidy[i][p] = (dphidxi[i][p]*dxidy_map[p] + dphideta[i][p]*detady_map[p] + dphidzeta[i][p]*dzetady_map[p]); // dphi/dz = (dphi/dxi)*(dxi/dz) + (dphi/deta)*(deta/dz) + (dphi/dzeta)*(dzeta/dz); dphi[i][p](2) = dphidz[i][p] = (dphidxi[i][p]*dxidz_map[p] + dphideta[i][p]*detadz_map[p] + dphidzeta[i][p]*dzetadz_map[p]); } // This is the derivative of the phase term of this infinite element for (unsigned int p=0; p<n_total_qp; p++) { // the derivative of the phase term dphase[p](0) = (dphasedxi[p] * dxidx_map[p] + dphasedeta[p] * detadx_map[p] + dphasedzeta[p] * dzetadx_map[p]); dphase[p](1) = (dphasedxi[p] * dxidy_map[p] + dphasedeta[p] * detady_map[p] + dphasedzeta[p] * dzetady_map[p]); dphase[p](2) = (dphasedxi[p] * dxidz_map[p] + dphasedeta[p] * detadz_map[p] + dphasedzeta[p] * dzetadz_map[p]); // the derivative of the radial weight - varies only in radial direction, // therefore dweightdxi = dweightdeta = 0. dweight[p](0) = dweightdv[p] * dzetadx_map[p]; dweight[p](1) = dweightdv[p] * dzetady_map[p]; dweight[p](2) = dweightdv[p] * dzetadz_map[p]; } break; } default: libmesh_error_msg("Unsupported dim = " << dim); } // Stop logging the overall computation of shape functions STOP_LOG("compute_shape_functions()", "InfFE"); }
void RBEIMEvaluation::legacy_write_offline_data_to_files(const std::string& directory_name, const bool read_binary_data) { START_LOG("legacy_write_offline_data_to_files()", "RBEIMEvaluation"); Parent::legacy_write_offline_data_to_files(directory_name); // Get the number of basis functions unsigned int n_bfs = get_n_basis_functions(); // The writing mode: ENCODE for binary, WRITE for ASCII XdrMODE mode = read_binary_data ? ENCODE : WRITE; // The suffix to use for all the files that are written out const std::string suffix = read_binary_data ? ".xdr" : ".dat"; if(this->processor_id() == 0) { std::ostringstream file_name; // Next write out the interpolation_matrix file_name.str(""); file_name << directory_name << "/interpolation_matrix" << suffix; Xdr interpolation_matrix_out(file_name.str(), mode); for(unsigned int i=0; i<n_bfs; i++) { for(unsigned int j=0; j<=i; j++) { interpolation_matrix_out << interpolation_matrix(i,j); } } // Also, write out the "extra" row file_name.str(""); file_name << directory_name << "/extra_interpolation_matrix_row" << suffix; Xdr extra_interpolation_matrix_row_out(file_name.str(), mode); for(unsigned int j=0; j<n_bfs; j++) { extra_interpolation_matrix_row_out << extra_interpolation_matrix_row(j); } extra_interpolation_matrix_row_out.close(); // Next write out interpolation_points file_name.str(""); file_name << directory_name << "/interpolation_points" << suffix; Xdr interpolation_points_out(file_name.str(), mode); for(unsigned int i=0; i<n_bfs; i++) { interpolation_points_out << interpolation_points[i](0); if(LIBMESH_DIM >= 2) interpolation_points_out << interpolation_points[i](1); if(LIBMESH_DIM >= 3) interpolation_points_out << interpolation_points[i](2); } interpolation_points_out.close(); // Also, write out the "extra" interpolation point file_name.str(""); file_name << directory_name << "/extra_interpolation_point" << suffix; Xdr extra_interpolation_point_out(file_name.str(), mode); extra_interpolation_point_out << extra_interpolation_point(0); if(LIBMESH_DIM >= 2) extra_interpolation_point_out << extra_interpolation_point(1); if(LIBMESH_DIM >= 3) extra_interpolation_point_out << extra_interpolation_point(2); extra_interpolation_point_out.close(); // Next write out interpolation_points_var file_name.str(""); file_name << directory_name << "/interpolation_points_var" << suffix; Xdr interpolation_points_var_out(file_name.str(), mode); for(unsigned int i=0; i<n_bfs; i++) { interpolation_points_var_out << interpolation_points_var[i]; } interpolation_points_var_out.close(); // Also, write out the "extra" interpolation variable file_name.str(""); file_name << directory_name << "/extra_interpolation_point_var" << suffix; Xdr extra_interpolation_point_var_out(file_name.str(), mode); extra_interpolation_point_var_out << extra_interpolation_point_var; extra_interpolation_point_var_out.close(); } // Write out the elements associated with the interpolation points. // This uses mesh I/O, hence we have to do it on all processors. legacy_write_out_interpolation_points_elem(directory_name); STOP_LOG("legacy_write_offline_data_to_files()", "RBEIMEvaluation"); }
void PointLocatorList::init () { libmesh_assert (!this->_list); if (this->_initialized) { libMesh::err << "ERROR: Already initialized! Will ignore this call..." << std::endl; } else { if (this->_master == NULL) { START_LOG("init(no master)", "PointLocatorList"); // We are the master, so we have to build the list. // First create it, then get a handy reference, and // then try to speed up by reserving space... this->_list = new std::vector<std::pair<Point, const Elem *> >; std::vector<std::pair<Point, const Elem *> >& my_list = *(this->_list); my_list.clear(); my_list.reserve(this->_mesh.n_active_elem()); // fill our list with the centroids and element // pointers of the mesh. For this use the handy // element iterators. // const_active_elem_iterator el (this->_mesh.elements_begin()); // const const_active_elem_iterator end(this->_mesh.elements_end()); MeshBase::const_element_iterator el = _mesh.active_elements_begin(); const MeshBase::const_element_iterator end = _mesh.active_elements_end(); for (; el!=end; ++el) my_list.push_back(std::make_pair((*el)->centroid(), *el)); STOP_LOG("init(no master)", "PointLocatorList"); } else { // We are _not_ the master. Let our _list point to // the master's list. But for this we first transform // the master in a state for which we are friends // (this should also beware of a bad master pointer?). // And make sure the master @e has a list! const PointLocatorList* my_master = libmesh_cast_ptr<const PointLocatorList*>(this->_master); if (my_master->initialized()) this->_list = my_master->_list; else { libMesh::err << "ERROR: Initialize master first, then servants!" << std::endl; libmesh_error(); } } } // ready for take-off this->_initialized = true; }
void ParmetisPartitioner::_do_repartition (MeshBase& mesh, const unsigned int n_sbdmns) { libmesh_assert_greater (n_sbdmns, 0); // Check for an easy return if (n_sbdmns == 1) { this->single_partition(mesh); return; } // This function must be run on all processors at once parallel_only(); // What to do if the Parmetis library IS NOT present #ifndef LIBMESH_HAVE_PARMETIS libmesh_here(); libMesh::err << "ERROR: The library has been built without" << std::endl << "Parmetis support. Using a Metis" << std::endl << "partitioner instead!" << std::endl; MetisPartitioner mp; mp.partition (mesh, n_sbdmns); // What to do if the Parmetis library IS present #else // Revert to METIS on one processor. if (libMesh::n_processors() == 1) { MetisPartitioner mp; mp.partition (mesh, n_sbdmns); return; } START_LOG("repartition()", "ParmetisPartitioner"); // Initialize the data structures required by ParMETIS this->initialize (mesh, n_sbdmns); // Make sure all processors have enough active local elements. // Parmetis tends to crash when it's given only a couple elements // per partition. { bool all_have_enough_elements = true; for (unsigned int pid=0; pid<_n_active_elem_on_proc.size(); pid++) if (_n_active_elem_on_proc[pid] < MIN_ELEM_PER_PROC) all_have_enough_elements = false; // Parmetis will not work unless each processor has some // elements. Specifically, it will abort when passed a NULL // partition array on *any* of the processors. if (!all_have_enough_elements) { // FIXME: revert to METIS, although this requires a serial mesh MeshSerializer serialize(mesh); STOP_LOG ("repartition()", "ParmetisPartitioner"); MetisPartitioner mp; mp.partition (mesh, n_sbdmns); return; } } // build the graph corresponding to the mesh this->build_graph (mesh); // Partition the graph std::vector<int> vsize(_vwgt.size(), 1); float itr = 1000000.0; MPI_Comm mpi_comm = libMesh::COMM_WORLD; // Call the ParMETIS adaptive repartitioning method. This respects the // original partitioning when computing the new partitioning so as to // minimize the required data redistribution. Parmetis::ParMETIS_V3_AdaptiveRepart(_vtxdist.empty() ? NULL : &_vtxdist[0], _xadj.empty() ? NULL : &_xadj[0], _adjncy.empty() ? NULL : &_adjncy[0], _vwgt.empty() ? NULL : &_vwgt[0], vsize.empty() ? NULL : &vsize[0], NULL, &_wgtflag, &_numflag, &_ncon, &_nparts, _tpwgts.empty() ? NULL : &_tpwgts[0], _ubvec.empty() ? NULL : &_ubvec[0], &itr, &_options[0], &_edgecut, _part.empty() ? NULL : &_part[0], &mpi_comm); // Assign the returned processor ids this->assign_partitioning (mesh); STOP_LOG ("repartition()", "ParmetisPartitioner"); #endif // #ifndef LIBMESH_HAVE_PARMETIS ... else ... }
void StatisticsVector<T>::histogram(std::vector<unsigned int>& bin_members, unsigned int n_bins) { // Must have at least 1 bin libmesh_assert (n_bins>0); const unsigned int n = this->size(); std::sort(this->begin(), this->end()); // The StatisticsVector can hold both integer and float types. // We will define all the bins, etc. using Reals. Real min = static_cast<Real>(this->minimum()); Real max = static_cast<Real>(this->maximum()); Real bin_size = (max - min) / static_cast<Real>(n_bins); START_LOG ("histogram()", "StatisticsVector"); std::vector<Real> bin_bounds(n_bins+1); for (unsigned int i=0; i<bin_bounds.size(); i++) bin_bounds[i] = min + i * bin_size; // Give the last bin boundary a little wiggle room: we don't want // it to be just barely less than the max, otherwise our bin test below // may fail. bin_bounds.back() += 1.e-6 * bin_size; // This vector will store the number of members each bin has. bin_members.resize(n_bins); unsigned int data_index = 0; for (unsigned int j=0; j<bin_members.size(); j++) // bin vector indexing { // libMesh::out << "(debug) Filling bin " << j << std::endl; for (unsigned int i=data_index; i<n; i++) // data vector indexing { // libMesh::out << "(debug) Processing index=" << i << std::endl; Real current_val = static_cast<Real>( (*this)[i] ); // There may be entries in the vector smaller than the value // reported by this->minimum(). (e.g. inactive elements in an // ErrorVector.) We just skip entries like that. if ( current_val < min ) { // libMesh::out << "(debug) Skipping entry v[" << i << "]=" // << (*this)[i] // << " which is less than the min value: min=" // << min << std::endl; continue; } if ( current_val > bin_bounds[j+1] ) // if outside the current bin (bin[j] is bounded // by bin_bounds[j] and bin_bounds[j+1]) { // libMesh::out.precision(16); // libMesh::out.setf(std::ios_base::fixed); // libMesh::out << "(debug) (*this)[i]= " << (*this)[i] // << " is greater than bin_bounds[j+1]=" // << bin_bounds[j+1] << std::endl; data_index = i; // start searching here for next bin break; // go to next bin } // Otherwise, increment current bin's count bin_members[j]++; // libMesh::out << "(debug) Binned index=" << i << std::endl; } } #ifdef DEBUG // Check the number of binned entries const unsigned int n_binned = std::accumulate(bin_members.begin(), bin_members.end(), static_cast<unsigned int>(0), std::plus<unsigned int>()); if (n != n_binned) { libMesh::out << "Warning: The number of binned entries, n_binned=" << n_binned << ", did not match the total number of entries, n=" << n << "." << std::endl; //libmesh_error(); } #endif STOP_LOG ("histogram()", "StatisticsVector"); }
double __libmesh_nlopt_objective(unsigned n, const double * x, double * gradient, void * data) { START_LOG("objective()", "NloptOptimizationSolver"); // ctx should be a pointer to the solver (it was passed in as void *) NloptOptimizationSolver<Number> * solver = static_cast<NloptOptimizationSolver<Number> *> (data); OptimizationSystem & sys = solver->system(); // We'll use current_local_solution below, so let's ensure that it's consistent // with the vector x that was passed in. for (unsigned int i=sys.solution->first_local_index(); i<sys.solution->last_local_index(); i++) sys.solution->set(i, x[i]); // Make sure the solution vector is parallel-consistent sys.solution->close(); // Impose constraints on X sys.get_dof_map().enforce_constraints_exactly(sys); // Update sys.current_local_solution based on X sys.update(); Real objective; if (solver->objective_object != NULL) { objective = solver->objective_object->objective( *(sys.current_local_solution), sys); } else { libmesh_error_msg("Objective function not defined in __libmesh_nlopt_objective"); } // If the gradient has been requested, fill it in if (gradient) { if (solver->gradient_object != NULL) { solver->gradient_object->gradient( *(sys.current_local_solution), *(sys.rhs), sys); // we've filled up sys.rhs with the gradient data, now copy it // to the nlopt data structure libmesh_assert(sys.rhs->size() == n); std::vector<double> grad; sys.rhs->localize_to_one(grad); for (unsigned i=0; i<n; ++i) gradient[i] = grad[i]; } else libmesh_error_msg("Gradient function not defined in __libmesh_nlopt_objective"); } STOP_LOG("objective()", "NloptOptimizationSolver"); // Increment the iteration count. solver->get_iteration_count()++; // Possibly print the current value of the objective function if (solver->verbose) libMesh::out << objective << std::endl; return objective; }
void RadialBasisInterpolation<KDDim,RBF>::prepare_for_use() { // Call base class methods for prep InverseDistanceInterpolation<KDDim>::prepare_for_use(); InverseDistanceInterpolation<KDDim>::construct_kd_tree(); #ifndef LIBMESH_HAVE_EIGEN libmesh_error_msg("ERROR: this functionality presently requires Eigen!"); #else START_LOG ("prepare_for_use()", "RadialBasisInterpolation<>"); // Construct a bounding box for our source points _src_bbox.invalidate(); const unsigned int n_src_pts = this->_src_pts.size(); const unsigned int n_vars = this->n_field_variables(); libmesh_assert_equal_to (this->_src_vals.size(), n_src_pts*this->n_field_variables()); { Point &p_min(_src_bbox.min()), &p_max(_src_bbox.max()); for (unsigned int p=0; p<n_src_pts; p++) { const Point &p_src(_src_pts[p]); for (unsigned int d=0; d<LIBMESH_DIM; d++) { p_min(d) = std::min(p_min(d), p_src(d)); p_max(d) = std::max(p_max(d), p_src(d)); } } } libMesh::out << "bounding box is \n" << _src_bbox.min() << '\n' << _src_bbox.max() << std::endl; // Construct the Radial Basis Function, giving it the size of the domain if(_r_override < 0) _r_bbox = (_src_bbox.max() - _src_bbox.min()).size(); else _r_bbox = _r_override; RBF rbf(_r_bbox); libMesh::out << "bounding box is \n" << _src_bbox.min() << '\n' << _src_bbox.max() << '\n' << "r_bbox = " << _r_bbox << '\n' << "rbf(r_bbox/2) = " << rbf(_r_bbox/2) << std::endl; // Construct the projection Matrix typedef Eigen::Matrix<Number, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor> DynamicMatrix; //typedef Eigen::Matrix<Number, Eigen::Dynamic, 1, Eigen::ColMajor> DynamicVector; DynamicMatrix A(n_src_pts, n_src_pts), x(n_src_pts,n_vars), b(n_src_pts,n_vars); for (unsigned int i=0; i<n_src_pts; i++) { const Point &x_i (_src_pts[i]); // Diagonal A(i,i) = rbf(0.); for (unsigned int j=i+1; j<n_src_pts; j++) { const Point &x_j (_src_pts[j]); const Real r_ij = (x_j - x_i).size(); A(i,j) = A(j,i) = rbf(r_ij); } // set source data for (unsigned int var=0; var<n_vars; var++) b(i,var) = _src_vals[i*n_vars + var]; } // Solve the linear system x = A.ldlt().solve(b); //x = A.fullPivLu().solve(b); // save the weights for each variable _weights.resize (this->_src_vals.size()); for (unsigned int i=0; i<n_src_pts; i++) for (unsigned int var=0; var<n_vars; var++) _weights[i*n_vars + var] = x(i,var); STOP_LOG ("prepare_for_use()", "RadialBasisInterpolation<>"); #endif }
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 = 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 = 0; dof_id_type optimal_elem_id = DofObject::invalid_id; // Initialize largest_abs_value to be negative so that it definitely gets updated. Real largest_abs_value = -1.; // Compute truth representation via projection MeshBase& mesh = this->get_mesh(); UniquePtr<DGFEMContext> c = this->build_context(); DGFEMContext &context = cast_ref<DGFEMContext&>(*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.get_element_qrule().n_points(); for(unsigned int qp=0; qp<n_qpoints; qp++) { Number value = context.interior_value(var, qp); Real abs_value = std::abs(value); if( abs_value > largest_abs_value ) { optimal_value = value; largest_abs_value = abs_value; optimal_var = var; optimal_elem_id = (*el)->id(); FEBase* elem_fe = NULL; context.get_element_fe( var, elem_fe ); optimal_point = elem_fe->get_xyz()[qp]; } } } } // Find out which processor has the largest of the abs values unsigned int proc_ID_index; this->comm().maxloc(largest_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, optimal_value, and optimal_elem_id this->comm().broadcast(optimal_var, proc_ID_index); this->comm().broadcast(optimal_value, proc_ID_index); this->comm().broadcast(optimal_elem_id, proc_ID_index); // In debug mode, assert that we found an optimal_elem_id libmesh_assert_not_equal_to(optimal_elem_id, DofObject::invalid_id); // 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); Elem* elem_ptr = mesh.elem(optimal_elem_id); eim_eval.interpolation_points_elem.push_back( elem_ptr ); NumericVector<Number>* new_bf = NumericVector<Number>::build(this->comm()).release(); new_bf->init (this->n_dofs(), this->n_local_dofs(), false, 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; eim_eval.extra_interpolation_point_elem = mesh.elem(optimal_elem_id); } STOP_LOG("enrich_RB_space()", "RBEIMConstruction"); }
// ------------------------------------------------------------ // MetisPartitioner implementation void MetisPartitioner::_do_partition (MeshBase& mesh, const unsigned int n_pieces) { libmesh_assert_greater (n_pieces, 0); libmesh_assert (mesh.is_serial()); // Check for an easy return if (n_pieces == 1) { this->single_partition (mesh); return; } // What to do if the Metis library IS NOT present #ifndef LIBMESH_HAVE_METIS libmesh_here(); libMesh::err << "ERROR: The library has been built without" << std::endl << "Metis support. Using a space-filling curve" << std::endl << "partitioner instead!" << std::endl; SFCPartitioner sfcp; sfcp.partition (mesh, n_pieces); // What to do if the Metis library IS present #else START_LOG("partition()", "MetisPartitioner"); const dof_id_type n_active_elem = mesh.n_active_elem(); // build the graph // std::vector<Metis::idx_t> options(5); std::vector<Metis::idx_t> vwgt(n_active_elem); std::vector<Metis::idx_t> part(n_active_elem); Metis::idx_t n = static_cast<Metis::idx_t>(n_active_elem), // number of "nodes" (elements) // in the graph // wgtflag = 2, // weights on vertices only, // // none on edges // numflag = 0, // C-style 0-based numbering nparts = static_cast<Metis::idx_t>(n_pieces), // number of subdomains to create edgecut = 0; // the numbers of edges cut by the // resulting partition // Set the options // options[0] = 0; // use default options // Metis will only consider the active elements. // We need to map the active element ids into a // contiguous range. Further, we want the unique range indexing to be // independent of the element ordering, otherwise a circular dependency // can result in which the partitioning depends on the ordering which // depends on the partitioning... vectormap<dof_id_type, dof_id_type> global_index_map; global_index_map.reserve (n_active_elem); { std::vector<dof_id_type> global_index; MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); MeshCommunication().find_global_indices (mesh.comm(), MeshTools::bounding_box(mesh), it, end, global_index); libmesh_assert_equal_to (global_index.size(), n_active_elem); for (std::size_t cnt=0; it != end; ++it) { const Elem *elem = *it; global_index_map.insert (std::make_pair(elem->id(), global_index[cnt++])); } libmesh_assert_equal_to (global_index_map.size(), n_active_elem); } // If we have boundary elements in this mesh, we want to account for // the connectivity between them and interior elements. We can find // interior elements from boundary elements, but we need to build up // a lookup map to do the reverse. typedef LIBMESH_BEST_UNORDERED_MAP<const Elem *, const Elem *> map_type; map_type interior_to_boundary_map; { MeshBase::const_element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; // If we don't have an interior_parent then there's nothing to look us // up. if ((elem->dim() >= LIBMESH_DIM) || !elem->interior_parent()) continue; // get all relevant interior elements std::set<const Elem*> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem*>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { // FIXME - non-const versions of the Elem set methods // would be nice Elem* neighbor = const_cast<Elem*>(*n_it); #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP) interior_to_boundary_map.insert (std::make_pair(neighbor, elem)); #else interior_to_boundary_map.insert (interior_to_boundary_map.begin(), std::make_pair(neighbor, elem)); #endif } } } // Invoke METIS, but only on processor 0. // Then broadcast the resulting decomposition if (mesh.processor_id() == 0) { METIS_CSR_Graph<Metis::idx_t> csr_graph; csr_graph.offsets.resize(n_active_elem+1, 0); // Local scope for these { // build the graph in CSR format. Note that // the edges in the graph will correspond to // face neighbors #ifdef LIBMESH_ENABLE_AMR std::vector<const Elem*> neighbors_offspring; #endif MeshBase::element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_elements_end(); #ifndef NDEBUG std::size_t graph_size=0; #endif // (1) first pass - get the row sizes for each element by counting the number // of face neighbors. Also populate the vwght array if necessary for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; const dof_id_type elem_global_index = global_index_map[elem->id()]; libmesh_assert_less (elem_global_index, vwgt.size()); // maybe there is a better weight? // The weight is used to define what a balanced graph is if(!_weights) vwgt[elem_global_index] = elem->n_nodes(); else vwgt[elem_global_index] = static_cast<Metis::idx_t>((*_weights)[elem->id()]); unsigned int num_neighbors = 0; // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (unsigned int ms=0; ms<elem->n_neighbors(); ms++) { const Elem* neighbor = elem->neighbor(ms); if (neighbor != NULL) { // If the neighbor is active treat it // as a connection if (neighbor->active()) num_neighbors++; #ifdef LIBMESH_ENABLE_AMR // Otherwise we need to find all of the // neighbor's children that are connected to // us and add them else { // The side of the neighbor to which // we are connected const unsigned int ns = neighbor->which_neighbor_am_i (elem); libmesh_assert_less (ns, neighbor->n_neighbors()); // Get all the active children (& grandchildren, etc...) // of the neighbor. // FIXME - this is the wrong thing, since we // should be getting the active family tree on // our side only. But adding too many graph // links may cause hanging nodes to tend to be // on partition interiors, which would reduce // communication overhead for constraint // equations, so we'll leave it. neighbor->active_family_tree (neighbors_offspring); // Get all the neighbor's children that // live on that side and are thus connected // to us for (unsigned int nc=0; nc<neighbors_offspring.size(); nc++) { const Elem* child = neighbors_offspring[nc]; // This does not assume a level-1 mesh. // Note that since children have sides numbered // coincident with the parent then this is a sufficient test. if (child->neighbor(ns) == elem) { libmesh_assert (child->active()); num_neighbors++; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } // Check for any interior neighbors if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent()) { // get all relevant interior elements std::set<const Elem*> neighbor_set; elem->find_interior_neighbors(neighbor_set); num_neighbors += neighbor_set.size(); } // Check for any boundary neighbors typedef map_type::iterator map_it_type; std::pair<map_it_type, map_it_type> bounds = interior_to_boundary_map.equal_range(elem); num_neighbors += std::distance(bounds.first, bounds.second); csr_graph.prep_n_nonzeros(elem_global_index, num_neighbors); #ifndef NDEBUG graph_size += num_neighbors; #endif } csr_graph.prepare_for_use(); // (2) second pass - fill the compressed adjacency array elem_it = mesh.active_elements_begin(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; const dof_id_type elem_global_index = global_index_map[elem->id()]; unsigned int connection=0; // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (unsigned int ms=0; ms<elem->n_neighbors(); ms++) { const Elem* neighbor = elem->neighbor(ms); if (neighbor != NULL) { // If the neighbor is active treat it // as a connection if (neighbor->active()) csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()]; #ifdef LIBMESH_ENABLE_AMR // Otherwise we need to find all of the // neighbor's children that are connected to // us and add them else { // The side of the neighbor to which // we are connected const unsigned int ns = neighbor->which_neighbor_am_i (elem); libmesh_assert_less (ns, neighbor->n_neighbors()); // Get all the active children (& grandchildren, etc...) // of the neighbor. neighbor->active_family_tree (neighbors_offspring); // Get all the neighbor's children that // live on that side and are thus connected // to us for (unsigned int nc=0; nc<neighbors_offspring.size(); nc++) { const Elem* child = neighbors_offspring[nc]; // This does not assume a level-1 mesh. // Note that since children have sides numbered // coincident with the parent then this is a sufficient test. if (child->neighbor(ns) == elem) { libmesh_assert (child->active()); csr_graph(elem_global_index, connection++) = global_index_map[child->id()]; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent()) { // get all relevant interior elements std::set<const Elem*> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem*>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { // FIXME - non-const versions of the Elem set methods // would be nice Elem* neighbor = const_cast<Elem*>(*n_it); csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()]; } } // Check for any boundary neighbors typedef map_type::iterator map_it_type; std::pair<map_it_type, map_it_type> bounds = interior_to_boundary_map.equal_range(elem); for (map_it_type it = bounds.first; it != bounds.second; ++it) { const Elem* neighbor = it->second; csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()]; } } // We create a non-empty vals for a disconnected graph, to // work around a segfault from METIS. libmesh_assert_equal_to (csr_graph.vals.size(), std::max(graph_size,std::size_t(1))); } // done building the graph Metis::idx_t ncon = 1; // Select which type of partitioning to create // Use recursive if the number of partitions is less than or equal to 8 if (n_pieces <= 8) Metis::METIS_PartGraphRecursive(&n, &ncon, &csr_graph.offsets[0], &csr_graph.vals[0], &vwgt[0], NULL, NULL, &nparts, NULL, NULL, NULL, &edgecut, &part[0]); // Otherwise use kway else Metis::METIS_PartGraphKway(&n, &ncon, &csr_graph.offsets[0], &csr_graph.vals[0], &vwgt[0], NULL, NULL, &nparts, NULL, NULL, NULL, &edgecut, &part[0]); } // end processor 0 part // Broadcase the resutling partition mesh.comm().broadcast(part); // Assign the returned processor ids. The part array contains // the processor id for each active element, but in terms of // the contiguous indexing we defined above { MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for (; it!=end; ++it) { Elem* elem = *it; libmesh_assert (global_index_map.count(elem->id())); const dof_id_type elem_global_index = global_index_map[elem->id()]; libmesh_assert_less (elem_global_index, part.size()); const processor_id_type elem_procid = static_cast<processor_id_type>(part[elem_global_index]); elem->processor_id() = elem_procid; } } STOP_LOG("partition()", "MetisPartitioner"); #endif }
void CondensedEigenSystem::solve() { START_LOG("solve()", "CondensedEigenSystem"); // If we haven't initialized any condensed dofs, // just use the default eigen_system if(!condensed_dofs_initialized) { STOP_LOG("solve()", "CondensedEigenSystem"); Parent::solve(); return; } // A reference to the EquationSystems EquationSystems& es = this->get_equation_systems(); // check that necessary parameters have been set libmesh_assert (es.parameters.have_parameter<unsigned int>("eigenpairs")); libmesh_assert (es.parameters.have_parameter<unsigned int>("basis vectors")); if (this->assemble_before_solve) // Assemble the linear system this->assemble (); // If we reach here, then there should be some non-condensed dofs libmesh_assert(!local_non_condensed_dofs_vector.empty()); // Now condense the matrices matrix_A->create_submatrix(*condensed_matrix_A, local_non_condensed_dofs_vector, local_non_condensed_dofs_vector); if(generalized()) { matrix_B->create_submatrix(*condensed_matrix_B, local_non_condensed_dofs_vector, local_non_condensed_dofs_vector); } // Get the tolerance for the solver and the maximum // number of iterations. Here, we simply adopt the linear solver // specific parameters. const Real tol = es.parameters.get<Real>("linear solver tolerance"); const unsigned int maxits = es.parameters.get<unsigned int>("linear solver maximum iterations"); const unsigned int nev = es.parameters.get<unsigned int>("eigenpairs"); const unsigned int ncv = es.parameters.get<unsigned int>("basis vectors"); std::pair<unsigned int, unsigned int> solve_data; // call the solver depending on the type of eigenproblem if ( generalized() ) { //in case of a generalized eigenproblem solve_data = eigen_solver->solve_generalized (*condensed_matrix_A,*condensed_matrix_B, nev, ncv, tol, maxits); } else { libmesh_assert (!matrix_B); //in case of a standard eigenproblem solve_data = eigen_solver->solve_standard (*condensed_matrix_A, nev, ncv, tol, maxits); } set_n_converged(solve_data.first); set_n_iterations(solve_data.second); STOP_LOG("solve()", "CondensedEigenSystem"); }
std::pair<unsigned int, Real> EigenSparseLinearSolver<T>::solve (SparseMatrix<T> &matrix_in, NumericVector<T> &solution_in, NumericVector<T> &rhs_in, const double tol, const unsigned int m_its) { START_LOG("solve()", "EigenSparseLinearSolver"); this->init (); // Make sure the data passed in are really Eigen types EigenSparseMatrix<T>& matrix = libmesh_cast_ref<EigenSparseMatrix<T>&>(matrix_in); EigenSparseVector<T>& solution = libmesh_cast_ref<EigenSparseVector<T>&>(solution_in); EigenSparseVector<T>& rhs = libmesh_cast_ref<EigenSparseVector<T>&>(rhs_in); // Close the matrix and vectors in case this wasn't already done. matrix.close(); solution.close(); rhs.close(); std::pair<unsigned int, Real> retval(0,0.); // Solve the linear system switch (this->_solver_type) { // Conjugate-Gradient case CG: { Eigen::ConjugateGradient<EigenSM> solver (matrix._mat); solver.setMaxIterations(m_its); solver.setTolerance(tol); solution._vec = solver.solveWithGuess(rhs._vec,solution._vec); libMesh::out << "#iterations: " << solver.iterations() << std::endl; libMesh::out << "estimated error: " << solver.error() << std::endl; retval = std::make_pair(solver.iterations(), solver.error()); break; } // Bi-Conjugate Gradient Stabilized case BICGSTAB: { Eigen::BiCGSTAB<EigenSM> solver (matrix._mat); solver.setMaxIterations(m_its); solver.setTolerance(tol); solution._vec = solver.solveWithGuess(rhs._vec,solution._vec); libMesh::out << "#iterations: " << solver.iterations() << std::endl; libMesh::out << "estimated error: " << solver.error() << std::endl; retval = std::make_pair(solver.iterations(), solver.error()); break; } // // Generalized Minimum Residual // case GMRES: // { // libmesh_not_implemented(); // break; // } // Unknown solver, use BICGSTAB default: { libMesh::err << "ERROR: Unsupported Eigen Solver: " << Utility::enum_to_string(this->_solver_type) << std::endl << "Continuing with BICGSTAB" << std::endl; this->_solver_type = BICGSTAB; STOP_LOG("solve()", "EigenSparseLinearSolver"); return this->solve (matrix, solution, rhs, tol, m_its); } } STOP_LOG("solve()", "EigenSparseLinearSolver"); return retval; }
void RBEvaluation::resize_data_structures(const unsigned int Nmax, bool resize_error_bound_data) { START_LOG("resize_data_structures()", "RBEvaluation"); if(Nmax < this->get_n_basis_functions()) libmesh_error_msg("Error: Cannot set Nmax to be less than the current number of basis functions."); // Resize/clear inner product matrix if(compute_RB_inner_product) RB_inner_product_matrix.resize(Nmax,Nmax); // Allocate dense matrices for RB solves RB_Aq_vector.resize(rb_theta_expansion->get_n_A_terms()); for(unsigned int q=0; q<rb_theta_expansion->get_n_A_terms(); q++) { // Initialize the memory for the RB matrices RB_Aq_vector[q].resize(Nmax,Nmax); } RB_Fq_vector.resize(rb_theta_expansion->get_n_F_terms()); for(unsigned int q=0; q<rb_theta_expansion->get_n_F_terms(); q++) { // Initialize the memory for the RB vectors RB_Fq_vector[q].resize(Nmax); } // Initialize the RB output vectors RB_output_vectors.resize(rb_theta_expansion->get_n_outputs()); for(unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++) { RB_output_vectors[n].resize(rb_theta_expansion->get_n_output_terms(n)); for(unsigned int q_l=0; q_l<rb_theta_expansion->get_n_output_terms(n); q_l++) { RB_output_vectors[n][q_l].resize(Nmax); } } // Initialize vectors storing output data RB_outputs.resize(rb_theta_expansion->get_n_outputs(), 0.); if(resize_error_bound_data) { // Initialize vectors for the norms of the Fq representors unsigned int Q_f_hat = rb_theta_expansion->get_n_F_terms()*(rb_theta_expansion->get_n_F_terms()+1)/2; Fq_representor_innerprods.resize(Q_f_hat); // Initialize vectors for the norms of the representors Fq_Aq_representor_innerprods.resize(rb_theta_expansion->get_n_F_terms()); for(unsigned int i=0; i<rb_theta_expansion->get_n_F_terms(); i++) { Fq_Aq_representor_innerprods[i].resize(rb_theta_expansion->get_n_A_terms()); for(unsigned int j=0; j<rb_theta_expansion->get_n_A_terms(); j++) { Fq_Aq_representor_innerprods[i][j].resize(Nmax, 0.); } } unsigned int Q_a_hat = rb_theta_expansion->get_n_A_terms()*(rb_theta_expansion->get_n_A_terms()+1)/2; Aq_Aq_representor_innerprods.resize(Q_a_hat); for(unsigned int i=0; i<Q_a_hat; i++) { Aq_Aq_representor_innerprods[i].resize(Nmax); for(unsigned int j=0; j<Nmax; j++) { Aq_Aq_representor_innerprods[i][j].resize(Nmax, 0.); } } RB_output_error_bounds.resize(rb_theta_expansion->get_n_outputs(), 0.); // Resize the output dual norm vectors output_dual_innerprods.resize(rb_theta_expansion->get_n_outputs()); for(unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++) { unsigned int Q_l_hat = rb_theta_expansion->get_n_output_terms(n)*(rb_theta_expansion->get_n_output_terms(n)+1)/2; output_dual_innerprods[n].resize(Q_l_hat); } // Clear and resize the vector of Aq_representors clear_riesz_representors(); Aq_representor.resize(rb_theta_expansion->get_n_A_terms()); for(unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++) { Aq_representor[q_a].resize(Nmax); } } STOP_LOG("resize_data_structures()", "RBEvaluation"); }
void FEXYZMap::compute_face_map(int dim, const std::vector<Real>& qw, const Elem* side) { libmesh_assert(side); START_LOG("compute_face_map()", "FEXYZMap"); // The number of quadrature points. const unsigned int n_qp = libmesh_cast_int<unsigned int>(qw.size()); switch(dim) { case 2: { // Resize the vectors to hold data at the quadrature points { this->xyz.resize(n_qp); this->dxyzdxi_map.resize(n_qp); this->d2xyzdxi2_map.resize(n_qp); this->tangents.resize(n_qp); this->normals.resize(n_qp); this->curvatures.resize(n_qp); this->JxW.resize(n_qp); } // Clear the entities that will be summed // Compute the tangent & normal at the quadrature point for (unsigned int p=0; p<n_qp; p++) { this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D this->xyz[p].zero(); this->dxyzdxi_map[p].zero(); this->d2xyzdxi2_map[p].zero(); } // compute x, dxdxi at the quadrature points for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes { const Point& side_point = side->point(i); for (unsigned int p=0; p<n_qp; p++) // for each quadrature point... { this->xyz[p].add_scaled (side_point, this->psi_map[i][p]); this->dxyzdxi_map[p].add_scaled (side_point, this->dpsidxi_map[i][p]); this->d2xyzdxi2_map[p].add_scaled(side_point, this->d2psidxi2_map[i][p]); } } // Compute the tangent & normal at the quadrature point for (unsigned int p=0; p<n_qp; p++) { const Point n(this->dxyzdxi_map[p](1), -this->dxyzdxi_map[p](0), 0.); this->normals[p] = n.unit(); this->tangents[p][0] = this->dxyzdxi_map[p].unit(); #if LIBMESH_DIM == 3 // Only good in 3D space this->tangents[p][1] = this->dxyzdxi_map[p].cross(n).unit(); #endif // The curvature is computed via the familiar Frenet formula: // curvature = [d^2(x) / d (xi)^2] dot [normal] // For a reference, see: // F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill, p. 310 // // Note: The sign convention here is different from the // 3D case. Concave-upward curves (smiles) have a positive // curvature. Concave-downward curves (frowns) have a // negative curvature. Be sure to take that into account! const Real numerator = this->d2xyzdxi2_map[p] * this->normals[p]; const Real denominator = this->dxyzdxi_map[p].size_sq(); libmesh_assert_not_equal_to (denominator, 0); this->curvatures[p] = numerator / denominator; } // compute the jacobian at the quadrature points for (unsigned int p=0; p<n_qp; p++) { const Real the_jac = std::sqrt(this->dxdxi_map(p)*this->dxdxi_map(p) + this->dydxi_map(p)*this->dydxi_map(p)); libmesh_assert_greater (the_jac, 0.); this->JxW[p] = the_jac*qw[p]; } break; } case 3: { // Resize the vectors to hold data at the quadrature points { this->xyz.resize(n_qp); this->dxyzdxi_map.resize(n_qp); this->dxyzdeta_map.resize(n_qp); this->d2xyzdxi2_map.resize(n_qp); this->d2xyzdxideta_map.resize(n_qp); this->d2xyzdeta2_map.resize(n_qp); this->tangents.resize(n_qp); this->normals.resize(n_qp); this->curvatures.resize(n_qp); this->JxW.resize(n_qp); } // Clear the entities that will be summed for (unsigned int p=0; p<n_qp; p++) { this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D this->xyz[p].zero(); this->dxyzdxi_map[p].zero(); this->dxyzdeta_map[p].zero(); this->d2xyzdxi2_map[p].zero(); this->d2xyzdxideta_map[p].zero(); this->d2xyzdeta2_map[p].zero(); } // compute x, dxdxi at the quadrature points for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes { const Point& side_point = side->point(i); for (unsigned int p=0; p<n_qp; p++) // for each quadrature point... { this->xyz[p].add_scaled (side_point, this->psi_map[i][p]); this->dxyzdxi_map[p].add_scaled (side_point, this->dpsidxi_map[i][p]); this->dxyzdeta_map[p].add_scaled (side_point, this->dpsideta_map[i][p]); this->d2xyzdxi2_map[p].add_scaled (side_point, this->d2psidxi2_map[i][p]); this->d2xyzdxideta_map[p].add_scaled(side_point, this->d2psidxideta_map[i][p]); this->d2xyzdeta2_map[p].add_scaled (side_point, this->d2psideta2_map[i][p]); } } // Compute the tangents, normal, and curvature at the quadrature point for (unsigned int p=0; p<n_qp; p++) { const Point n = this->dxyzdxi_map[p].cross(this->dxyzdeta_map[p]); this->normals[p] = n.unit(); this->tangents[p][0] = this->dxyzdxi_map[p].unit(); this->tangents[p][1] = n.cross(this->dxyzdxi_map[p]).unit(); // Compute curvature using the typical nomenclature // of the first and second fundamental forms. // For reference, see: // 1) http://mathworld.wolfram.com/MeanCurvature.html // (note -- they are using inward normal) // 2) F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill const Real L = -this->d2xyzdxi2_map[p] * this->normals[p]; const Real M = -this->d2xyzdxideta_map[p] * this->normals[p]; const Real N = -this->d2xyzdeta2_map[p] * this->normals[p]; const Real E = this->dxyzdxi_map[p].size_sq(); const Real F = this->dxyzdxi_map[p] * this->dxyzdeta_map[p]; const Real G = this->dxyzdeta_map[p].size_sq(); const Real numerator = E*N -2.*F*M + G*L; const Real denominator = E*G - F*F; libmesh_assert_not_equal_to (denominator, 0.); this->curvatures[p] = 0.5*numerator/denominator; } // compute the jacobian at the quadrature points, see // http://sp81.msi.umn.edu:999/fluent/fidap/help/theory/thtoc.htm for (unsigned int p=0; p<n_qp; p++) { const Real g11 = (this->dxdxi_map(p)*this->dxdxi_map(p) + this->dydxi_map(p)*this->dydxi_map(p) + this->dzdxi_map(p)*this->dzdxi_map(p)); const Real g12 = (this->dxdxi_map(p)*this->dxdeta_map(p) + this->dydxi_map(p)*this->dydeta_map(p) + this->dzdxi_map(p)*this->dzdeta_map(p)); const Real g21 = g12; const Real g22 = (this->dxdeta_map(p)*this->dxdeta_map(p) + this->dydeta_map(p)*this->dydeta_map(p) + this->dzdeta_map(p)*this->dzdeta_map(p)); const Real the_jac = std::sqrt(g11*g22 - g12*g21); libmesh_assert_greater (the_jac, 0.); this->JxW[p] = the_jac*qw[p]; } break; } default: libmesh_error(); } // switch(dim) STOP_LOG("compute_face_map()", "FEXYZMap"); return; }
Real RBEvaluation::compute_residual_dual_norm(const unsigned int N) { START_LOG("compute_residual_dual_norm()", "RBEvaluation"); const RBParameters& mu = get_parameters(); // Use the stored representor inner product values // to evaluate the residual norm Number residual_norm_sq = 0.; unsigned int q=0; for(unsigned int q_f1=0; q_f1<rb_theta_expansion->get_n_F_terms(); q_f1++) { for(unsigned int q_f2=q_f1; q_f2<rb_theta_expansion->get_n_F_terms(); q_f2++) { Real delta = (q_f1==q_f2) ? 1. : 2.; residual_norm_sq += delta * libmesh_real( rb_theta_expansion->eval_F_theta(q_f1, mu) * libmesh_conj(rb_theta_expansion->eval_F_theta(q_f2, mu)) * Fq_representor_innerprods[q] ); q++; } } for(unsigned int q_f=0; q_f<rb_theta_expansion->get_n_F_terms(); q_f++) { for(unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++) { for(unsigned int i=0; i<N; i++) { Real delta = 2.; residual_norm_sq += delta * libmesh_real( rb_theta_expansion->eval_F_theta(q_f, mu) * libmesh_conj(rb_theta_expansion->eval_A_theta(q_a, mu)) * libmesh_conj(RB_solution(i)) * Fq_Aq_representor_innerprods[q_f][q_a][i] ); } } } q=0; for(unsigned int q_a1=0; q_a1<rb_theta_expansion->get_n_A_terms(); q_a1++) { for(unsigned int q_a2=q_a1; q_a2<rb_theta_expansion->get_n_A_terms(); q_a2++) { Real delta = (q_a1==q_a2) ? 1. : 2.; for(unsigned int i=0; i<N; i++) { for(unsigned int j=0; j<N; j++) { residual_norm_sq += delta * libmesh_real( libmesh_conj(rb_theta_expansion->eval_A_theta(q_a1, mu)) * rb_theta_expansion->eval_A_theta(q_a2, mu) * libmesh_conj(RB_solution(i)) * RB_solution(j) * Aq_Aq_representor_innerprods[q][i][j] ); } } q++; } } if(libmesh_real(residual_norm_sq) < 0.) { // libMesh::out << "Warning: Square of residual norm is negative " // << "in RBSystem::compute_residual_dual_norm()" << std::endl; // Sometimes this is negative due to rounding error, // but when this occurs the error is on the order of 1.e-10, // so shouldn't affect error bound much... residual_norm_sq = std::abs(residual_norm_sq); } STOP_LOG("compute_residual_dual_norm()", "RBEvaluation"); return std::sqrt( libmesh_real(residual_norm_sq) ); }
void UNVIO::count_nodes (std::istream& in_file) { START_LOG("count_nodes()","UNVIO"); // if this->_n_nodes is not 0 the dataset // has already been scanned if (this->_n_nodes != 0) { libMesh::err << "Error: Trying to scan nodes twice!" << std::endl; libmesh_error(); } // Read from file, count nodes, // check if floats have to be converted std::string data; in_file >> data; // read the first node label if (data == "-1") { libMesh::err << "ERROR: Bad, already reached end of dataset before even starting to read nodes!" << std::endl; libmesh_error(); } // ignore the misc data for this node in_file.ignore(256,'\n'); // Now we are there to verify whether we need // to convert from D to e or not in_file >> data; // When this "data" contains a "D", then // we have to convert each and every float... // But also assume when _this_ specific // line does not contain a "D", then the // other lines won't, too. { // #ifdef __HP_aCC // // Use an "int" instead of unsigned int, // // otherwise HP aCC may crash! // const int position = data.find("D",6); // #else // const unsigned int position = data.find("D",6); // #endif std::string::size_type position = data.find("D",6); if (position!=std::string::npos) // npos means no position { this->_need_D_to_e = true; if (this->verbose()) libMesh::out << " Convert from \"D\" to \"e\"" << std::endl; } else this->_need_D_to_e = false; } // read the remaining two coordinates in_file >> data; in_file >> data; // this was our first node this->_n_nodes++; // proceed _counting_ the remaining // nodes. while (in_file.good()) { // read the node label in_file >> data; if (data == "-1") // end of dataset is reached break; // ignore the remaining data (coord_sys_label, color etc) in_file.ignore (256, '\n'); // ignore the coordinates in_file.ignore (256, '\n'); this->_n_nodes++; } if (in_file.eof()) { libMesh::err << "ERROR: File ended before end of node dataset!" << std::endl; libmesh_error(); } if (this->verbose()) libMesh::out << " Nodes : " << this->_n_nodes << std::endl; STOP_LOG("count_nodes()","UNVIO"); }