Tree<N>::Tree (const MeshBase & m, unsigned int target_bin_size, const Trees::BuildType bt) : TreeBase(m), root(m,target_bin_size), build_type(bt) { // Set the root node bounding box equal to the bounding // box for the entire domain. root.set_bounding_box (MeshTools::bounding_box(mesh)); if (build_type == Trees::NODES) { // Add all the nodes to the root node. It will // automagically build the tree for us. MeshBase::const_node_iterator it = mesh.nodes_begin(); const MeshBase::const_node_iterator end = mesh.nodes_end(); for (; it != end; ++it) { #ifndef NDEBUG bool node_was_inserted = #endif root.insert (*it); libmesh_assert(node_was_inserted); } // Now the tree contains the nodes. // However, we want element pointers, so here we // convert between the two. std::vector<std::vector<const Elem *> > nodes_to_elem; MeshTools::build_nodes_to_elem_map (mesh, nodes_to_elem); root.transform_nodes_to_elements (nodes_to_elem); } else if (build_type == Trees::ELEMENTS) { // Add all active elements to the root node. It will // automatically build the tree for us. MeshBase::const_element_iterator it = mesh.active_elements_begin(); const MeshBase::const_element_iterator end = mesh.active_elements_end(); for (; it != end; ++it) { #ifndef NDEBUG bool elem_was_inserted = #endif root.insert (*it); libmesh_assert(elem_was_inserted); } } else if (build_type == Trees::LOCAL_ELEMENTS) { // Add all active, local elements to the root node. It will // automatically build the tree for us. MeshBase::const_element_iterator it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end = mesh.active_local_elements_end(); for (; it != end; ++it) { #ifndef NDEBUG bool elem_was_inserted = #endif root.insert (*it); libmesh_assert(elem_was_inserted); } } else libmesh_error_msg("Unknown build_type = " << build_type); }
void FEXYZ<Dim>::compute_face_values(const Elem * elem, const Elem * side, const std::vector<Real> & qw) { libmesh_assert(elem); libmesh_assert(side); START_LOG("compute_face_values()", "FEXYZ"); // The number of quadrature points. const std::size_t n_qp = qw.size(); // Number of shape functions in the finite element approximation // space. const unsigned int n_approx_shape_functions = this->n_shape_functions(this->get_type(), this->get_order()); // Resize the shape functions and their gradients this->phi.resize (n_approx_shape_functions); this->dphi.resize (n_approx_shape_functions); this->dphidx.resize (n_approx_shape_functions); this->dphidy.resize (n_approx_shape_functions); this->dphidz.resize (n_approx_shape_functions); for (unsigned int i=0; i<n_approx_shape_functions; i++) { this->phi[i].resize (n_qp); this->dphi[i].resize (n_qp); this->dphidx[i].resize (n_qp); this->dphidy[i].resize (n_qp); this->dphidz[i].resize (n_qp); } this->_fe_map->compute_face_map(this->dim, qw, side); const std::vector<libMesh::Point> & xyz = this->_fe_map->get_xyz(); switch (this->dim) { // 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. case 2: { // compute the shape function values & gradients for (unsigned int i=0; i<n_approx_shape_functions; i++) for (std::size_t p=0; p<n_qp; p++) { this->phi[i][p] = FE<Dim,XYZ>::shape (elem, this->fe_type.order, i, xyz[p]); this->dphi[i][p](0) = this->dphidx[i][p] = FE<Dim,XYZ>::shape_deriv (elem, this->fe_type.order, i, 0, xyz[p]); this->dphi[i][p](1) = this->dphidy[i][p] = FE<Dim,XYZ>::shape_deriv (elem, this->fe_type.order, i, 1, xyz[p]); #if LIBMESH_DIM == 3 this->dphi[i][p](2) = // can only assign to the Z component if LIBMESH_DIM==3 #endif this->dphidz[i][p] = 0.; } // done computing face values break; } // A 3D finite element living in 3D space. case 3: { // compute the shape function values & gradients for (unsigned int i=0; i<n_approx_shape_functions; i++) for (std::size_t p=0; p<n_qp; p++) { this->phi[i][p] = FE<Dim,XYZ>::shape (elem, this->fe_type.order, i, xyz[p]); this->dphi[i][p](0) = this->dphidx[i][p] = FE<Dim,XYZ>::shape_deriv (elem, this->fe_type.order, i, 0, xyz[p]); this->dphi[i][p](1) = this->dphidy[i][p] = FE<Dim,XYZ>::shape_deriv (elem, this->fe_type.order, i, 1, xyz[p]); this->dphi[i][p](2) = this->dphidz[i][p] = FE<Dim,XYZ>::shape_deriv (elem, this->fe_type.order, i, 2, xyz[p]); } // done computing face values break; } default: libmesh_error_msg("Invalid dim " << this->dim); } STOP_LOG("compute_face_values()", "FEXYZ"); }
Real FE<3,MONOMIAL>::shape_second_deriv(const ElemType, const Order libmesh_dbg_var(order), const unsigned int i, const unsigned int j, const Point& p) { #if LIBMESH_DIM == 3 libmesh_assert_less (j, 6); libmesh_assert_less (i, (static_cast<unsigned int>(order)+1)* (static_cast<unsigned int>(order)+2)* (static_cast<unsigned int>(order)+3)/6); const Real xi = p(0); const Real eta = p(1); const Real zeta = p(2); // monomials. since they are hierarchic we only need one case block. switch (j) { // d^2()/dxi^2 case 0: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: return 2.; case 5: case 6: case 7: case 8: case 9: return 0.; // cubic case 10: return 6.*xi; case 11: return 2.*eta; case 12: case 13: return 0.; case 14: return 2.*zeta; case 15: case 16: case 17: case 18: case 19: return 0.; // quartics case 20: return 12.*xi*xi; case 21: return 6.*xi*eta; case 22: return 2.*eta*eta; case 23: case 24: return 0.; case 25: return 6.*xi*zeta; case 26: return 2.*eta*zeta; case 27: case 28: return 0.; case 29: return 2.*zeta*zeta; case 30: case 31: case 32: case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nx * (nx - 1); for (unsigned int index=2; index < nx; index++) val *= xi; for (unsigned int index=0; index != ny; index++) val *= eta; for (unsigned int index=0; index != nz; index++) val *= zeta; return val; } } // d^2()/dxideta case 1: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: return 0.; case 5: return 1.; case 6: case 7: case 8: case 9: return 0.; // cubic case 10: return 0.; case 11: return 2.*xi; case 12: return 2.*eta; case 13: case 14: return 0.; case 15: return zeta; case 16: case 17: case 18: case 19: return 0.; // quartics case 20: return 0.; case 21: return 3.*xi*xi; case 22: return 4.*xi*eta; case 23: return 3.*eta*eta; case 24: case 25: return 0.; case 26: return 2.*xi*zeta; case 27: return 2.*eta*zeta; case 28: case 29: return 0.; case 30: return zeta*zeta; case 31: case 32: case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nx * ny; for (unsigned int index=1; index < nx; index++) val *= xi; for (unsigned int index=1; index < ny; index++) val *= eta; for (unsigned int index=0; index != nz; index++) val *= zeta; return val; } } // d^2()/deta^2 case 2: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: return 0.; case 6: return 2.; case 7: case 8: case 9: return 0.; // cubic case 10: case 11: return 0.; case 12: return 2.*xi; case 13: return 6.*eta; case 14: case 15: return 0.; case 16: return 2.*zeta; case 17: case 18: case 19: return 0.; // quartics case 20: case 21: return 0.; case 22: return 2.*xi*xi; case 23: return 6.*xi*eta; case 24: return 12.*eta*eta; case 25: case 26: return 0.; case 27: return 2.*xi*zeta; case 28: return 6.*eta*zeta; case 29: case 30: return 0.; case 31: return 2.*zeta*zeta; case 32: case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = ny * (ny - 1); for (unsigned int index=0; index != nx; index++) val *= xi; for (unsigned int index=2; index < ny; index++) val *= eta; for (unsigned int index=0; index != nz; index++) val *= zeta; return val; } } // d^2()/dxidzeta case 3: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: case 6: return 0.; case 7: return 1.; case 8: case 9: return 0.; // cubic case 10: case 11: case 12: case 13: return 0.; case 14: return 2.*xi; case 15: return eta; case 16: return 0.; case 17: return 2.*zeta; case 18: case 19: return 0.; // quartics case 20: case 21: case 22: case 23: case 24: return 0.; case 25: return 3.*xi*xi; case 26: return 2.*xi*eta; case 27: return eta*eta; case 28: return 0.; case 29: return 4.*xi*zeta; case 30: return 2.*eta*zeta; case 31: return 0.; case 32: return 3.*zeta*zeta; case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nx * nz; for (unsigned int index=1; index < nx; index++) val *= xi; for (unsigned int index=0; index != ny; index++) val *= eta; for (unsigned int index=1; index < nz; index++) val *= zeta; return val; } } // d^2()/detadzeta case 4: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: case 6: case 7: return 0.; case 8: return 1.; case 9: return 0.; // cubic case 10: case 11: case 12: case 13: case 14: return 0.; case 15: return xi; case 16: return 2.*eta; case 17: return 0.; case 18: return 2.*zeta; case 19: return 0.; // quartics case 20: case 21: case 22: case 23: case 24: case 25: return 0.; case 26: return xi*xi; case 27: return 2.*xi*eta; case 28: return 3.*eta*eta; case 29: return 0.; case 30: return 2.*xi*zeta; case 31: return 4.*eta*zeta; case 32: return 0.; case 33: return 3.*zeta*zeta; case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = ny * nz; for (unsigned int index=0; index != nx; index++) val *= xi; for (unsigned int index=1; index < ny; index++) val *= eta; for (unsigned int index=1; index < nz; index++) val *= zeta; return val; } } // d^2()/dzeta^2 case 5: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: case 6: case 7: case 8: return 0.; case 9: return 2.; // cubic case 10: case 11: case 12: case 13: case 14: case 15: case 16: return 0.; case 17: return 2.*xi; case 18: return 2.*eta; case 19: return 6.*zeta; // quartics case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: return 0.; case 29: return 2.*xi*xi; case 30: return 2.*xi*eta; case 31: return 2.*eta*eta; case 32: return 6.*xi*zeta; case 33: return 6.*eta*zeta; case 34: return 12.*zeta*zeta; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nz * (nz - 1); for (unsigned int index=0; index != nx; index++) val *= xi; for (unsigned int index=0; index != ny; index++) val *= eta; for (unsigned int index=2; index < nz; index++) val *= zeta; return val; } } default: libmesh_error_msg("Invalid j = " << j); } #endif libmesh_error_msg("We'll never get here!"); return 0.; }
Real RBEvaluation::rb_solve(unsigned int N) { LOG_SCOPE("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); } return abs_error_bound; } else // Don't calculate the error bounds { // Just return -1. if we did not compute the error bound return -1.; } }
Real InfHex::quality (const ElemQuality q) const { switch (q) { /** * Compue the min/max diagonal ratio. * Source: CUBIT User's Manual. * * For infinite elements, we just only compute * the diagonal in the face... * Don't know whether this makes sense, * but should be a feasible way. */ case DIAGONAL: { // Diagonal between node 0 and node 2 const Real d02 = this->length(0,2); // Diagonal between node 1 and node 3 const Real d13 = this->length(1,3); // Find the biggest and smallest diagonals const Real min = std::min(d02, d13); const Real max = std::max(d02, d13); libmesh_assert_not_equal_to (max, 0.0); return min / max; break; } /** * Minimum ratio of lengths derived from opposite edges. * Source: CUBIT User's Manual. * * For IFEMs, do this only for the base face... * Does this make sense? */ case TAPER: { /** * Compute the side lengths. */ const Real d01 = this->length(0,1); const Real d12 = this->length(1,2); const Real d23 = this->length(2,3); const Real d03 = this->length(0,3); std::vector<Real> edge_ratios(2); // Bottom edge_ratios[8] = std::min(d01, d23) / std::max(d01, d23); edge_ratios[9] = std::min(d03, d12) / std::max(d03, d12); return *(std::min_element(edge_ratios.begin(), edge_ratios.end())) ; break; } /** * Minimum edge length divided by max diagonal length. * Source: CUBIT User's Manual. * * And again, we mess around a bit, for the IFEMs... * Do this only for the base. */ case STRETCH: { /** * Should this be a sqrt2, when we do this for the base only? */ const Real sqrt3 = 1.73205080756888; /** * Compute the maximum diagonal in the base. */ const Real d02 = this->length(0,2); const Real d13 = this->length(1,3); const Real max_diag = std::max(d02, d13); libmesh_assert_not_equal_to ( max_diag, 0.0 ); /** * Compute the minimum edge length in the base. */ std::vector<Real> edges(4); edges[0] = this->length(0,1); edges[1] = this->length(1,2); edges[2] = this->length(2,3); edges[3] = this->length(0,3); const Real min_edge = *(std::min_element(edges.begin(), edges.end())); return sqrt3 * min_edge / max_diag ; } /** * I don't know what to do for this metric. * Maybe the base class knows... */ default: return Elem::quality(q); } libmesh_error_msg("We'll never get here!"); return 0.; }
void ExodusII_IO::set_coordinate_offset(Point) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
void RBEvaluation::read_in_vectors_from_multiple_files(System & sys, std::vector< std::vector<NumericVector<Number> *> * > multiple_vectors, const std::vector<std::string> & multiple_directory_names, const std::vector<std::string> & multiple_data_names, const bool read_binary_vectors) { LOG_SCOPE("read_in_vectors_from_multiple_files()", "RBEvaluation"); unsigned int n_files = multiple_vectors.size(); unsigned int n_directories = multiple_directory_names.size(); unsigned int n_data_names = multiple_data_names.size(); libmesh_assert( (n_files == n_directories) && (n_files == n_data_names) ); if (n_files == 0) return; // Make sure processors are synced up before we begin this->comm().barrier(); std::ostringstream file_name; const std::string basis_function_suffix = (read_binary_vectors ? ".xdr" : ".dat"); struct stat stat_info; // Assume that all the headers are the same, hence we can just use the first one. file_name << multiple_directory_names[0] << "/" << multiple_data_names[0] << "_header" << basis_function_suffix; assert_file_exists(file_name.str()); Xdr header_data(file_name.str(), read_binary_vectors ? DECODE : READ); // set the version number in header_data from io_version_string // (same code as in EquationSystemsIO::_read_impl) std::string io_version_string = get_io_version_string(); std::string::size_type lm_pos = io_version_string.find("libMesh"); std::istringstream iss(io_version_string.substr(lm_pos + 8)); int ver_major = 0, ver_minor = 0, ver_patch = 0; char dot; iss >> ver_major >> dot >> ver_minor >> dot >> ver_patch; header_data.set_version(LIBMESH_VERSION_ID(ver_major, ver_minor, ver_patch)); // We need to call sys.read_header (e.g. to set _written_var_indices properly), // but by setting the read_header argument to false, it doesn't reinitialize the system sys.read_header(header_data, io_version_string, /*read_header=*/false, /*read_additional_data=*/false); // Following EquationSystemsIO::read, we use a temporary numbering (node major) // before writing out the data MeshTools::Private::globally_renumber_nodes_and_elements(sys.get_mesh()); for (unsigned int data_index=0; data_index<n_directories; data_index++) { std::vector<NumericVector<Number> *> & vectors = *multiple_vectors[data_index]; // Allocate storage for each vector for (unsigned int i=0; i<vectors.size(); i++) { // vectors should all be NULL, otherwise we get a memory leak when // we create the new vectors in RBEvaluation::read_in_vectors. if (vectors[i]) libmesh_error_msg("Non-NULL vector passed to read_in_vectors_from_multiple_files"); vectors[i] = NumericVector<Number>::build(sys.comm()).release(); vectors[i]->init (sys.n_dofs(), sys.n_local_dofs(), false, PARALLEL); } file_name.str(""); file_name << multiple_directory_names[data_index] << "/" << multiple_data_names[data_index] << "_data" << basis_function_suffix; // On processor zero check to be sure the file exists if (this->processor_id() == 0) { int stat_result = stat(file_name.str().c_str(), &stat_info); if (stat_result != 0) libmesh_error_msg("File does not exist: " << file_name.str()); } assert_file_exists(file_name.str()); Xdr vector_data(file_name.str(), read_binary_vectors ? DECODE : READ); // The vector_data needs to know which version to read. vector_data.set_version(LIBMESH_VERSION_ID(ver_major, ver_minor, ver_patch)); sys.read_serialized_vectors (vector_data, vectors); } // Undo the temporary renumbering sys.get_mesh().fix_broken_node_and_element_numbering(); }
void ExodusII_IO::write_global_data (const std::vector<Number> &, const std::vector<std::string> &) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
void ExodusII_IO::write_nodal_data_discontinuous (const std::string &, const std::vector<Number> &, const std::vector<std::string> &) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
void ExodusII_IO::write_element_data (const EquationSystems &) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
void ExodusII_IO::write_information_records (const std::vector<std::string> &) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
int ExodusII_IO::get_num_time_steps() { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
const std::vector<Real> & ExodusII_IO::get_time_steps() { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
Real Hex::quality (const ElemQuality q) const { switch (q) { /** * Compue the min/max diagonal ratio. * Source: CUBIT User's Manual. */ case DIAGONAL: { // Diagonal between node 0 and node 6 const Real d06 = this->length(0,6); // Diagonal between node 3 and node 5 const Real d35 = this->length(3,5); // Diagonal between node 1 and node 7 const Real d17 = this->length(1,7); // Diagonal between node 2 and node 4 const Real d24 = this->length(2,4); // Find the biggest and smallest diagonals const Real min = std::min(d06, std::min(d35, std::min(d17, d24))); const Real max = std::max(d06, std::max(d35, std::max(d17, d24))); libmesh_assert_not_equal_to (max, 0.0); return min / max; break; } /** * Minimum ratio of lengths derived from opposite edges. * Source: CUBIT User's Manual. */ case TAPER: { /** * Compute the side lengths. */ const Real d01 = this->length(0,1); const Real d12 = this->length(1,2); const Real d23 = this->length(2,3); const Real d03 = this->length(0,3); const Real d45 = this->length(4,5); const Real d56 = this->length(5,6); const Real d67 = this->length(6,7); const Real d47 = this->length(4,7); const Real d04 = this->length(0,4); const Real d15 = this->length(1,5); const Real d37 = this->length(3,7); const Real d26 = this->length(2,6); std::vector<Real> edge_ratios(12); // Front edge_ratios[0] = std::min(d01, d45) / std::max(d01, d45); edge_ratios[1] = std::min(d04, d15) / std::max(d04, d15); // Right edge_ratios[2] = std::min(d15, d26) / std::max(d15, d26); edge_ratios[3] = std::min(d12, d56) / std::max(d12, d56); // Back edge_ratios[4] = std::min(d67, d23) / std::max(d67, d23); edge_ratios[5] = std::min(d26, d37) / std::max(d26, d37); // Left edge_ratios[6] = std::min(d04, d37) / std::max(d04, d37); edge_ratios[7] = std::min(d03, d47) / std::max(d03, d47); // Bottom edge_ratios[8] = std::min(d01, d23) / std::max(d01, d23); edge_ratios[9] = std::min(d03, d12) / std::max(d03, d12); // Top edge_ratios[10] = std::min(d45, d67) / std::max(d45, d67); edge_ratios[11] = std::min(d56, d47) / std::max(d56, d47); return *(std::min_element(edge_ratios.begin(), edge_ratios.end())) ; break; } /** * Minimum edge length divided by max diagonal length. * Source: CUBIT User's Manual. */ case STRETCH: { const Real sqrt3 = 1.73205080756888; /** * Compute the maximum diagonal. */ const Real d06 = this->length(0,6); const Real d17 = this->length(1,7); const Real d35 = this->length(3,5); const Real d24 = this->length(2,4); const Real max_diag = std::max(d06, std::max(d17, std::max(d35, d24))); libmesh_assert_not_equal_to ( max_diag, 0.0 ); /** * Compute the minimum edge length. */ std::vector<Real> edges(12); edges[0] = this->length(0,1); edges[1] = this->length(1,2); edges[2] = this->length(2,3); edges[3] = this->length(0,3); edges[4] = this->length(4,5); edges[5] = this->length(5,6); edges[6] = this->length(6,7); edges[7] = this->length(4,7); edges[8] = this->length(0,4); edges[9] = this->length(1,5); edges[10] = this->length(2,6); edges[11] = this->length(3,7); const Real min_edge = *(std::min_element(edges.begin(), edges.end())); return sqrt3 * min_edge / max_diag ; } /** * I don't know what to do for this metric. * Maybe the base class knows... */ default: return Elem::quality(q); } libmesh_error_msg("We'll never get here!"); return 0.; }
void ExodusII_IO::use_mesh_dimension_instead_of_spatial_dimension(bool) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
void ExodusII_IO::write_nodal_data_common(std::string, const std::vector<std::string> &, bool) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
void ExodusII_IO::write_as_dimension(unsigned) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
void ExodusII_IO::read (const std::string & fname) { // Get a reference to the mesh we are reading MeshBase & mesh = MeshInput<MeshBase>::mesh(); // Clear any existing mesh data mesh.clear(); // Keep track of what kinds of elements this file contains elems_of_dimension.clear(); elems_of_dimension.resize(4, false); #ifdef DEBUG this->verbose(true); #endif // Instantiate the ElementMaps interface ExodusII_IO_Helper::ElementMaps em(*exio_helper); // Open the exodus file in EX_READ mode exio_helper->open(fname.c_str(), /*read_only=*/true); // Get header information from exodus file exio_helper->read_header(); // Read the QA records exio_helper->read_qa_records(); // Print header information exio_helper->print_header(); // Read nodes from the exodus file exio_helper->read_nodes(); // Reserve space for the nodes. mesh.reserve_nodes(exio_helper->num_nodes); // Read the node number map from the Exodus file. This is // required if we want to preserve the numbering of nodes as it // exists in the Exodus file. If the Exodus file does not contain // a node_num_map, the identity map is returned by this call. exio_helper->read_node_num_map(); // Loop over the nodes, create Nodes with local processor_id 0. for (int i=0; i<exio_helper->num_nodes; i++) { // Use the node_num_map to get the correct ID for Exodus int exodus_id = exio_helper->node_num_map[i]; // Catch the node that was added to the mesh Node * added_node = mesh.add_point (Point(exio_helper->x[i], exio_helper->y[i], exio_helper->z[i]), exodus_id-1); // If the Mesh assigned an ID different from what is in the // Exodus file, we should probably error. if (added_node->id() != static_cast<unsigned>(exodus_id-1)) libmesh_error_msg("Error! Mesh assigned node ID " \ << added_node->id() \ << " which is different from the (zero-based) Exodus ID " \ << exodus_id-1 \ << "!"); } // This assert is no longer valid if the nodes are not numbered // sequentially starting from 1 in the Exodus file. // libmesh_assert_equal_to (static_cast<unsigned int>(exio_helper->num_nodes), mesh.n_nodes()); // Get information about all the blocks exio_helper->read_block_info(); // Reserve space for the elements mesh.reserve_elem(exio_helper->num_elem); // Read the element number map from the Exodus file. This is // required if we want to preserve the numbering of elements as it // exists in the Exodus file. If the Exodus file does not contain // an elem_num_map, the identity map is returned by this call. exio_helper->read_elem_num_map(); // Read in the element connectivity for each block. int nelem_last_block = 0; // Loop over all the blocks for (int i=0; i<exio_helper->num_elem_blk; i++) { // Read the information for block i exio_helper->read_elem_in_block (i); int subdomain_id = exio_helper->get_block_id(i); // populate the map of names std::string subdomain_name = exio_helper->get_block_name(i); if (!subdomain_name.empty()) mesh.subdomain_name(static_cast<subdomain_id_type>(subdomain_id)) = subdomain_name; // Set any relevant node/edge maps for this element const std::string type_str (exio_helper->get_elem_type()); const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(type_str); // Loop over all the faces in this block int jmax = nelem_last_block+exio_helper->num_elem_this_blk; for (int j=nelem_last_block; j<jmax; j++) { Elem * elem = Elem::build (conv.get_canonical_type()).release(); libmesh_assert (elem); elem->subdomain_id() = static_cast<subdomain_id_type>(subdomain_id) ; // Use the elem_num_map to obtain the ID of this element in the Exodus file int exodus_id = exio_helper->elem_num_map[j]; // Assign this element the same ID it had in the Exodus // file, but make it zero-based by subtracting 1. Note: // some day we could use 1-based numbering in libmesh and // thus match the Exodus numbering exactly, but at the // moment libmesh is zero-based. elem->set_id(exodus_id-1); // Record that we have seen an element of dimension elem->dim() elems_of_dimension[elem->dim()] = true; // Catch the Elem pointer that the Mesh throws back elem = mesh.add_elem (elem); // If the Mesh assigned an ID different from what is in the // Exodus file, we should probably error. if (elem->id() != static_cast<unsigned>(exodus_id-1)) libmesh_error_msg("Error! Mesh assigned ID " \ << elem->id() \ << " which is different from the (zero-based) Exodus ID " \ << exodus_id-1 \ << "!"); // Set all the nodes for this element for (int k=0; k<exio_helper->num_nodes_per_elem; k++) { // global index int gi = (j-nelem_last_block)*exio_helper->num_nodes_per_elem + conv.get_node_map(k); // The entries in 'connect' are actually (1-based) // indices into the node_num_map, so to get the right // node ID we: // 1.) Subtract 1 from connect[gi] // 2.) Pass it through node_num_map to get the corresponding Exodus ID // 3.) Subtract 1 from that, since libmesh node numbering is "zero"-based, // even when the Exodus node numbering doesn't start with 1. int libmesh_node_id = exio_helper->node_num_map[exio_helper->connect[gi] - 1] - 1; // Set the node pointer in the Elem elem->set_node(k) = mesh.node_ptr(libmesh_node_id); } } // running sum of # of elements per block, // (should equal total number of elements in the end) nelem_last_block += exio_helper->num_elem_this_blk; } // This assert isn't valid if the Exodus file's numbering doesn't // start with 1! For example, if Exodus's elem_num_map is 21, 22, // 23, 24, 25, 26, 27, 28, 29, 30, ... 84, then by the time you are // done with the loop above, mesh.n_elem() will report 84 and // nelem_last_block will be 64. // libmesh_assert_equal_to (static_cast<unsigned>(nelem_last_block), mesh.n_elem()); // Set the mesh dimension to the largest encountered for an element for (unsigned char i=0; i!=4; ++i) if (elems_of_dimension[i]) mesh.set_mesh_dimension(i); // Read in sideset information -- this is useful for applying boundary conditions { // Get basic information about all sidesets exio_helper->read_sideset_info(); int offset=0; for (int i=0; i<exio_helper->num_side_sets; i++) { // Compute new offset offset += (i > 0 ? exio_helper->num_sides_per_set[i-1] : 0); exio_helper->read_sideset (i, offset); std::string sideset_name = exio_helper->get_side_set_name(i); if (!sideset_name.empty()) mesh.get_boundary_info().sideset_name (cast_int<boundary_id_type>(exio_helper->get_side_set_id(i))) = sideset_name; } for (unsigned int e=0; e<exio_helper->elem_list.size(); e++) { // The numbers in the Exodus file sidesets should be thought // of as (1-based) indices into the elem_num_map array. So, // to get the right element ID we have to: // 1.) Subtract 1 from elem_list[e] (to get a zero-based index) // 2.) Pass it through elem_num_map (to get the corresponding Exodus ID) // 3.) Subtract 1 from that, since libmesh is "zero"-based, // even when the Exodus numbering doesn't start with 1. dof_id_type libmesh_elem_id = cast_int<dof_id_type>(exio_helper->elem_num_map[exio_helper->elem_list[e] - 1] - 1); // Set any relevant node/edge maps for this element Elem * elem = mesh.elem(libmesh_elem_id); const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(elem->type()); // Map the zero-based Exodus side numbering to the libmesh side numbering int mapped_side = conv.get_side_map(exio_helper->side_list[e]-1); // Check for errors if (mapped_side == ExodusII_IO_Helper::Conversion::invalid_id) libmesh_error_msg("Invalid 1-based side id: " \ << exio_helper->side_list[e] \ << " detected for " \ << Utility::enum_to_string(elem->type())); // Add this (elem,side,id) triplet to the BoundaryInfo object. mesh.get_boundary_info().add_side (libmesh_elem_id, cast_int<unsigned short>(mapped_side), cast_int<boundary_id_type>(exio_helper->id_list[e])); } } // Read nodeset info { exio_helper->read_nodeset_info(); for (int nodeset=0; nodeset<exio_helper->num_node_sets; nodeset++) { boundary_id_type nodeset_id = cast_int<boundary_id_type>(exio_helper->nodeset_ids[nodeset]); std::string nodeset_name = exio_helper->get_node_set_name(nodeset); if (!nodeset_name.empty()) mesh.get_boundary_info().nodeset_name(nodeset_id) = nodeset_name; exio_helper->read_nodeset(nodeset); for (unsigned int node=0; node<exio_helper->node_list.size(); node++) { // As before, the entries in 'node_list' are 1-based // indcies into the node_num_map array, so we have to map // them. See comment above. int libmesh_node_id = exio_helper->node_num_map[exio_helper->node_list[node] - 1] - 1; mesh.get_boundary_info().add_node(cast_int<dof_id_type>(libmesh_node_id), nodeset_id); } } } #if LIBMESH_DIM < 3 if (mesh.mesh_dimension() > LIBMESH_DIM) libmesh_error_msg("Cannot open dimension " \ << mesh.mesh_dimension() \ << " mesh file when configured without " \ << mesh.mesh_dimension() \ << "D support."); #endif }
void ExodusII_IO::append(bool) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
const std::vector<std::string> & ExodusII_IO::get_nodal_var_names() { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
void RBEvaluation::resize_data_structures(const unsigned int Nmax, bool resize_error_bound_data) { LOG_SCOPE("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); } } }
void ExodusII_IO::write_element_data (const EquationSystems & es) { // Be sure the file has been opened for writing! if (MeshOutput<MeshBase>::mesh().processor_id() == 0 && !exio_helper->opened_for_writing) libmesh_error_msg("ERROR, ExodusII file must be initialized before outputting element variables."); // This function currently only works on SerialMeshes. We rely on // having a reference to a non-const MeshBase object from our // MeshInput parent class to construct a MeshSerializer object, // similar to what is done in ExodusII_IO::write(). Note that // calling ExodusII_IO::write_timestep() followed by // ExodusII_IO::write_element_data() when the underlying Mesh is a // ParallelMesh will result in an unnecessary additional // serialization/re-parallelization step. MeshSerializer serialize(MeshInput<MeshBase>::mesh(), !MeshOutput<MeshBase>::_is_parallel_format); // To be (possibly) filled with a filtered list of variable names to output. std::vector<std::string> names; // If _output_variables is populated, only output the monomials which are // also in the _output_variables vector. if (_output_variables.size() > 0) { std::vector<std::string> monomials; const FEType type(CONSTANT, MONOMIAL); // Create a list of monomial variable names es.build_variable_names(monomials, &type); // Filter that list against the _output_variables list. Note: if names is still empty after // all this filtering, all the monomial variables will be gathered std::vector<std::string>::iterator it = monomials.begin(); for (; it!=monomials.end(); ++it) if (std::find(_output_variables.begin(), _output_variables.end(), *it) != _output_variables.end()) names.push_back(*it); } // If we pass in a list of names to "get_solution" it'll filter the variables coming back std::vector<Number> soln; es.get_solution(soln, names); if(soln.empty()) // If there is nothing to write just return return; // The data must ultimately be written block by block. This means that this data // must be sorted appropriately. if(MeshOutput<MeshBase>::mesh().processor_id()) return; const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); #ifdef LIBMESH_USE_COMPLEX_NUMBERS std::vector<std::string> complex_names = exio_helper->get_complex_names(names); exio_helper->initialize_element_variables(complex_names); unsigned int num_values = soln.size(); unsigned int num_vars = names.size(); unsigned int num_elems = num_values / num_vars; // This will contain the real and imaginary parts and the magnitude // of the values in soln std::vector<Real> complex_soln(3*num_values); for (unsigned i=0; i<num_vars; ++i) { for (unsigned int j=0; j<num_elems; ++j) { Number value = soln[i*num_vars + j]; complex_soln[3*i*num_elems + j] = value.real(); } for (unsigned int j=0; j<num_elems; ++j) { Number value = soln[i*num_vars + j]; complex_soln[3*i*num_elems + num_elems +j] = value.imag(); } for (unsigned int j=0; j<num_elems; ++j) { Number value = soln[i*num_vars + j]; complex_soln[3*i*num_elems + 2*num_elems + j] = std::abs(value); } } exio_helper->write_element_values(mesh, complex_soln, _timestep); #else exio_helper->initialize_element_variables(names); exio_helper->write_element_values(mesh, soln, _timestep); #endif }
void RBEvaluation::assert_file_exists(const std::string & file_name) { if (!std::ifstream(file_name.c_str())) libmesh_error_msg("File missing: " + file_name); }
ExodusII_IO::~ExodusII_IO () { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
/** * Returns all valid quality metrics for * element type t. */ std::vector<ElemQuality> Quality::valid(const ElemType t) { std::vector<ElemQuality> v; switch (t) { case EDGE2: case EDGE3: case EDGE4: { // None yet break; } case TRI3: case TRISHELL3: case TRI6: { v.resize(7); v[0] = MAX_ANGLE; v[1] = MIN_ANGLE; v[2] = CONDITION; v[3] = JACOBIAN; v[4] = SIZE; v[5] = SHAPE; v[6] = DISTORTION; break; } case QUAD4: case QUADSHELL4: case QUAD8: case QUADSHELL8: case QUAD9: { v.resize(13); v[0] = ASPECT_RATIO; v[1] = SKEW; v[2] = TAPER; v[3] = WARP; v[4] = STRETCH; v[5] = MIN_ANGLE; v[6] = MAX_ANGLE; v[7] = CONDITION; v[8] = JACOBIAN; v[9] = SHEAR; v[10] = SHAPE; v[11] = SIZE; v[12] = DISTORTION; break; } case TET4: case TET10: { v.resize(7); v[0] = ASPECT_RATIO_BETA; v[1] = ASPECT_RATIO_GAMMA; v[2] = CONDITION; v[3] = JACOBIAN; v[4] = SHAPE; v[5] = SIZE; v[6] = DISTORTION; break; } case HEX8: case HEX20: case HEX27: { v.resize(11); v[0] = ASPECT_RATIO; v[1] = SKEW; v[2] = SHEAR; v[3] = SHAPE; v[4] = CONDITION; v[5] = JACOBIAN; v[6] = DISTORTION; v[7] = TAPER; v[8] = STRETCH; v[9] = DIAGONAL; v[10] = SIZE; break; } case PRISM6: case PRISM18: { // None yet break; } case PYRAMID5: case PYRAMID13: case PYRAMID14: { // None yet break; } #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS case INFEDGE2: { // None yet break; } case INFQUAD4: case INFQUAD6: { // None yet break; } case INFHEX8: case INFHEX16: case INFHEX18: { // None yet break; } case INFPRISM6: case INFPRISM12: { // None yet break; } #endif default: libmesh_error_msg("Undefined element type!"); } return v; }
void ExodusII_IO::read (const std::string &) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
Real FE<3,MONOMIAL>::shape(const ElemType, const Order libmesh_dbg_var(order), const unsigned int i, const Point& p) { #if LIBMESH_DIM == 3 const Real xi = p(0); const Real eta = p(1); const Real zeta = p(2); libmesh_assert_less (i, (static_cast<unsigned int>(order)+1)* (static_cast<unsigned int>(order)+2)* (static_cast<unsigned int>(order)+3)/6); // monomials. since they are hierarchic we only need one case block. switch (i) { // constant case 0: return 1.; // linears case 1: return xi; case 2: return eta; case 3: return zeta; // quadratics case 4: return xi*xi; case 5: return xi*eta; case 6: return eta*eta; case 7: return xi*zeta; case 8: return zeta*eta; case 9: return zeta*zeta; // cubics case 10: return xi*xi*xi; case 11: return xi*xi*eta; case 12: return xi*eta*eta; case 13: return eta*eta*eta; case 14: return xi*xi*zeta; case 15: return xi*eta*zeta; case 16: return eta*eta*zeta; case 17: return xi*zeta*zeta; case 18: return eta*zeta*zeta; case 19: return zeta*zeta*zeta; // quartics case 20: return xi*xi*xi*xi; case 21: return xi*xi*xi*eta; case 22: return xi*xi*eta*eta; case 23: return xi*eta*eta*eta; case 24: return eta*eta*eta*eta; case 25: return xi*xi*xi*zeta; case 26: return xi*xi*eta*zeta; case 27: return xi*eta*eta*zeta; case 28: return eta*eta*eta*zeta; case 29: return xi*xi*zeta*zeta; case 30: return xi*eta*zeta*zeta; case 31: return eta*eta*zeta*zeta; case 32: return xi*zeta*zeta*zeta; case 33: return eta*zeta*zeta*zeta; case 34: return zeta*zeta*zeta*zeta; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = 1.; for (unsigned int index=0; index != nx; index++) val *= xi; for (unsigned int index=0; index != ny; index++) val *= eta; for (unsigned int index=0; index != nz; index++) val *= zeta; return val; } #endif libmesh_error_msg("We'll never get here!"); return 0.; }
void ExodusII_IO::verbose (bool) { libmesh_error_msg("ERROR, ExodusII API is not defined."); }
void ParmetisPartitioner::initialize (const MeshBase & mesh, const unsigned int n_sbdmns) { const dof_id_type n_active_local_elem = mesh.n_active_local_elem(); // Set parameters. _pmetis->wgtflag = 2; // weights on vertices only _pmetis->ncon = 1; // one weight per vertex _pmetis->numflag = 0; // C-style 0-based numbering _pmetis->nparts = static_cast<Parmetis::idx_t>(n_sbdmns); // number of subdomains to create _pmetis->edgecut = 0; // the numbers of edges cut by the // partition // Initialize data structures for ParMETIS _pmetis->vtxdist.resize (mesh.n_processors()+1); std::fill (_pmetis->vtxdist.begin(), _pmetis->vtxdist.end(), 0); _pmetis->tpwgts.resize (_pmetis->nparts); std::fill (_pmetis->tpwgts.begin(), _pmetis->tpwgts.end(), 1./_pmetis->nparts); _pmetis->ubvec.resize (_pmetis->ncon); std::fill (_pmetis->ubvec.begin(), _pmetis->ubvec.end(), 1.05); _pmetis->part.resize (n_active_local_elem); std::fill (_pmetis->part.begin(), _pmetis->part.end(), 0); _pmetis->options.resize (5); _pmetis->vwgt.resize (n_active_local_elem); // Set the options _pmetis->options[0] = 1; // don't use default options _pmetis->options[1] = 0; // default (level of timing) _pmetis->options[2] = 15; // random seed (default) _pmetis->options[3] = 2; // processor distribution and subdomain distribution are decoupled // Find the number of active elements on each processor. We cannot use // mesh.n_active_elem_on_proc(pid) since that only returns the number of // elements assigned to pid which are currently stored on the calling // processor. This will not in general be correct for parallel meshes // when (pid!=mesh.processor_id()). _n_active_elem_on_proc.resize(mesh.n_processors()); mesh.comm().allgather(n_active_local_elem, _n_active_elem_on_proc); // count the total number of active elements in the mesh. Note we cannot // use mesh.n_active_elem() in general since this only returns the number // of active elements which are stored on the calling processor. // We should not use n_active_elem for any allocation because that will // be inheritly unscalable, but it can be useful for libmesh_assertions. dof_id_type n_active_elem=0; // Set up the vtxdist array. This will be the same on each processor. // ***** Consult the Parmetis documentation. ***** libmesh_assert_equal_to (_pmetis->vtxdist.size(), cast_int<std::size_t>(mesh.n_processors()+1)); libmesh_assert_equal_to (_pmetis->vtxdist[0], 0); for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { _pmetis->vtxdist[pid+1] = _pmetis->vtxdist[pid] + _n_active_elem_on_proc[pid]; n_active_elem += _n_active_elem_on_proc[pid]; } libmesh_assert_equal_to (_pmetis->vtxdist.back(), static_cast<Parmetis::idx_t>(n_active_elem)); // ParMetis expects the elements to be numbered in contiguous blocks // by processor, i.e. [0, ne0), [ne0, ne0+ne1), ... // Since we only partition active elements we should have no expectation // that we currently have such a distribution. So we need to create it. // Also, at the same time we are going to map all the active elements into a globally // unique range [0,n_active_elem) which is *independent* of the current partitioning. // This can be fed to ParMetis as the initial partitioning of the subdomains (decoupled // from the partitioning of the objects themselves). This allows us to get the same // resultant partitioning independed of the input partitioning. MeshTools::BoundingBox bbox = MeshTools::bounding_box(mesh); _global_index_by_pid_map.clear(); // Maps active element ids into a contiguous range independent of partitioning. // (only needs local scope) vectormap<dof_id_type, dof_id_type> global_index_map; { std::vector<dof_id_type> global_index; // create the mapping which is contiguous by processor dof_id_type pid_offset=0; for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { MeshBase::const_element_iterator it = mesh.active_pid_elements_begin(pid); const MeshBase::const_element_iterator end = mesh.active_pid_elements_end(pid); // note that we may not have all (or any!) the active elements which belong on this processor, // but by calling this on all processors a unique range in [0,_n_active_elem_on_proc[pid]) // is constructed. Only the indices for the elements we pass in are returned in the array. MeshCommunication().find_global_indices (mesh.comm(), bbox, it, end, global_index); for (dof_id_type cnt=0; it != end; ++it) { const Elem * elem = *it; libmesh_assert (!_global_index_by_pid_map.count(elem->id())); libmesh_assert_less (cnt, global_index.size()); libmesh_assert_less (global_index[cnt], _n_active_elem_on_proc[pid]); _global_index_by_pid_map.insert(std::make_pair(elem->id(), global_index[cnt++] + pid_offset)); } pid_offset += _n_active_elem_on_proc[pid]; } // create the unique mapping for all active elements independent of partitioning { MeshBase::const_element_iterator it = mesh.active_elements_begin(); const MeshBase::const_element_iterator end = mesh.active_elements_end(); // Calling this on all processors a unique range in [0,n_active_elem) is constructed. // Only the indices for the elements we pass in are returned in the array. MeshCommunication().find_global_indices (mesh.comm(), bbox, it, end, global_index); for (dof_id_type cnt=0; it != end; ++it) { const Elem * elem = *it; libmesh_assert (!global_index_map.count(elem->id())); libmesh_assert_less (cnt, global_index.size()); libmesh_assert_less (global_index[cnt], n_active_elem); global_index_map.insert(std::make_pair(elem->id(), global_index[cnt++])); } } // really, shouldn't be close! libmesh_assert_less_equal (global_index_map.size(), n_active_elem); libmesh_assert_less_equal (_global_index_by_pid_map.size(), n_active_elem); // At this point the two maps should be the same size. If they are not // then the number of active elements is not the same as the sum over all // processors of the number of active elements per processor, which means // there must be some unpartitioned objects out there. if (global_index_map.size() != _global_index_by_pid_map.size()) libmesh_error_msg("ERROR: ParmetisPartitioner cannot handle unpartitioned objects!"); } // Finally, we need to initialize the vertex (partition) weights and the initial subdomain // mapping. The subdomain mapping will be independent of the processor mapping, and is // defined by a simple mapping of the global indices we just found. { std::vector<dof_id_type> subdomain_bounds(mesh.n_processors()); const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()]; for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { dof_id_type tgt_subdomain_size = 0; // watch out for the case that n_subdomains < n_processors if (pid < static_cast<unsigned int>(_pmetis->nparts)) { tgt_subdomain_size = n_active_elem/std::min (cast_int<Parmetis::idx_t>(mesh.n_processors()), _pmetis->nparts); if (pid < n_active_elem%_pmetis->nparts) tgt_subdomain_size++; } if (pid == 0) subdomain_bounds[0] = tgt_subdomain_size; else subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size; } libmesh_assert_equal_to (subdomain_bounds.back(), n_active_elem); 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) { const Elem * elem = *elem_it; libmesh_assert (_global_index_by_pid_map.count(elem->id())); const dof_id_type global_index_by_pid = _global_index_by_pid_map[elem->id()]; libmesh_assert_less (global_index_by_pid, n_active_elem); const dof_id_type local_index = global_index_by_pid - first_local_elem; libmesh_assert_less (local_index, n_active_local_elem); libmesh_assert_less (local_index, _pmetis->vwgt.size()); // TODO:[BSK] maybe there is a better weight? _pmetis->vwgt[local_index] = elem->n_nodes(); // find the subdomain this element belongs in libmesh_assert (global_index_map.count(elem->id())); const dof_id_type global_index = global_index_map[elem->id()]; libmesh_assert_less (global_index, subdomain_bounds.back()); const unsigned int subdomain_id = std::distance(subdomain_bounds.begin(), std::lower_bound(subdomain_bounds.begin(), subdomain_bounds.end(), global_index)); libmesh_assert_less (subdomain_id, static_cast<unsigned int>(_pmetis->nparts)); libmesh_assert_less (local_index, _pmetis->part.size()); _pmetis->part[local_index] = subdomain_id; } } }
RealGradient FE<3,NEDELEC_ONE>::shape_second_deriv(const Elem* elem, const Order order, const unsigned int i, const unsigned int j, const Point& libmesh_dbg_var(p)) { #if LIBMESH_DIM == 3 libmesh_assert(elem); // j = 0 ==> d^2 phi / dxi^2 // j = 1 ==> d^2 phi / dxi deta // j = 2 ==> d^2 phi / deta^2 // j = 3 ==> d^2 phi / dxi dzeta // j = 4 ==> d^2 phi / deta dzeta // j = 5 ==> d^2 phi / dzeta^2 libmesh_assert_less (j, 6); const Order totalorder = static_cast<Order>(order + elem->p_level()); switch (totalorder) { // linear Lagrange shape functions case FIRST: { switch (elem->type()) { case HEX20: case HEX27: { libmesh_assert_less (i, 12); #ifndef NDEBUG const Real xi = p(0); const Real eta = p(1); const Real zeta = p(2); #endif libmesh_assert_less_equal ( std::fabs(xi), 1.0+TOLERANCE ); libmesh_assert_less_equal ( std::fabs(eta), 1.0+TOLERANCE ); libmesh_assert_less_equal ( std::fabs(zeta), 1.0+TOLERANCE ); switch (j) { // d^2()/dxi^2 case 0: { // All d^2()/dxi^2 derivatives for linear hexes are zero. return RealGradient(); } // j=0 // d^2()/dxideta case 1: { switch(i) { case 0: case 1: case 2: case 3: case 8: case 9: case 10: case 11: return RealGradient(); case 4: { if( elem->point(0) > elem->point(4) ) return RealGradient( 0.0, 0.0, -0.125 ); else return RealGradient( 0.0, 0.0, 0.125 ); } case 5: { if( elem->point(1) > elem->point(5) ) return RealGradient( 0.0, 0.0, 0.125 ); else return RealGradient( 0.0, 0.0, -0.125 ); } case 6: { if( elem->point(2) > elem->point(6) ) return RealGradient( 0.0, 0.0, -0.125 ); else return RealGradient( 0.0, 0.0, 0.125 ); } case 7: { if( elem->point(3) > elem->point(7) ) return RealGradient( 0.0, 0.0, 0.125 ); else return RealGradient( 0.0, 0.0, -0.125 ); } default: libmesh_error_msg("Invalid i = " << i); } // switch(i) } // j=1 // d^2()/deta^2 case 2: { // All d^2()/deta^2 derivatives for linear hexes are zero. return RealGradient(); } // j = 2 // d^2()/dxidzeta case 3: { switch(i) { case 0: case 2: case 4: case 5: case 6: case 7: case 8: case 10: return RealGradient(); case 1: { if( elem->point(1) > elem->point(2) ) return RealGradient( 0.0, 0.125 ); else return RealGradient( 0.0, -0.125 ); } case 3: { if( elem->point(3) > elem->point(0) ) return RealGradient( 0.0, -0.125 ); else return RealGradient( 0.0, 0.125 ); } case 9: { if( elem->point(5) > elem->point(6) ) return RealGradient( 0.0, -0.125, 0.0 ); else return RealGradient( 0.0, 0.125, 0.0 ); } case 11: { if( elem->point(4) > elem->point(7) ) return RealGradient( 0.0, 0.125, 0.0 ); else return RealGradient( 0.0, -0.125, 0.0 ); } default: libmesh_error_msg("Invalid i = " << i); } // switch(i) } // j = 3 // d^2()/detadzeta case 4: { switch(i) { case 1: case 3: case 4: case 5: case 6: case 7: case 9: case 11: return RealGradient(); case 0: { if( elem->point(0) > elem->point(1) ) return RealGradient( -0.125, 0.0, 0.0 ); else return RealGradient( 0.125, 0.0, 0.0 ); } case 2: { if( elem->point(2) > elem->point(3) ) return RealGradient( 0.125, 0.0, 0.0 ); else return RealGradient( -0.125, 0.0, 0.0 ); } case 8: { if( elem->point(4) > elem->point(5) ) return RealGradient( 0.125, 0.0, 0.0 ); else return RealGradient( -0.125, 0.0, 0.0 ); } case 10: { if( elem->point(7) > elem->point(6) ) return RealGradient( -0.125, 0.0, 0.0 ); else return RealGradient( 0.125, 0.0, 0.0 ); } default: libmesh_error_msg("Invalid i = " << i); } // switch(i) } // j = 4 // d^2()/dzeta^2 case 5: { // All d^2()/dzeta^2 derivatives for linear hexes are zero. return RealGradient(); } // j = 5 default: libmesh_error_msg("Invalid j = " << j); } return RealGradient(); } case TET10: { libmesh_assert_less (i, 6); libmesh_not_implemented(); return RealGradient(); } default: libmesh_error_msg("ERROR: Unsupported 3D element type!: " << elem->type()); } //switch(type) } // case FIRST: // unsupported order default: libmesh_error_msg("ERROR: Unsupported 3D FE order!: " << totalorder); } #endif libmesh_error_msg("We'll never get here!"); return RealGradient(); }