/* * \brief This constructor will pull the mesh data DTK needs out of Moab, * partition it for the example, and build a DataTransferKit::MeshContainer * object from the local data in the partition. You can directly write the * traits interface yourself, but this is probably the easiest way to get * started (although potentially inefficient). */ MoabMesh::MoabMesh( const RCP_Comm& comm, const std::string& filename, const moab::EntityType& block_topology, const int partitioning_type ) : d_comm( comm ) { // Compute the node dimension. int node_dim = 0; if ( block_topology == moab::MBTRI ) { node_dim = 2; } else if ( block_topology == moab::MBQUAD ) { node_dim = 2; } else if ( block_topology == moab::MBTET ) { node_dim = 3; } else if ( block_topology == moab::MBHEX ) { node_dim = 3; } else if ( block_topology == moab::MBPYRAMID ) { node_dim = 3; } else { node_dim = 0; } // Create a moab instance. moab::ErrorCode error; d_moab = Teuchos::rcp( new moab::Core() ); std::cout<<"Filename: "<<filename<<std::endl; // Load the mesh. d_moab->load_mesh( &filename[0] ); moab::EntityHandle root_set = d_moab->get_root_set(); // Extract the elements with this block's topology. std::vector<moab::EntityHandle> global_elements; error = d_moab->get_entities_by_type( root_set, block_topology, global_elements ); assert( error == moab::MB_SUCCESS ); std::cout<<"Global elements: "<<global_elements.size()<<std::endl; // Partition the mesh. int comm_size = d_comm->getSize(); int comm_rank = d_comm->getRank(); // Get the number of nodes in an element. std::vector<moab::EntityHandle> elem_vertices; error = d_moab->get_adjacencies( &global_elements[0], 1, 0, false, elem_vertices ); assert( error == moab::MB_SUCCESS ); int nodes_per_element = elem_vertices.size(); // Get the global element coordinates. std::vector<double> global_coords; error = d_moab->get_vertex_coordinates( global_coords ); assert( error == moab::MB_SUCCESS ); // Get the global max and min values for the coordinates. This problem is // symmetric. double min = *(std::min_element( global_coords.begin(), global_coords.end() ) ); double max = *(std::max_element( global_coords.begin(), global_coords.end() ) ); double width = max - min; Teuchos::Array<moab::EntityHandle> elements; elem_vertices.resize( nodes_per_element ); std::vector<double> elem_coords( 3*nodes_per_element ); std::vector<moab::EntityHandle>::const_iterator global_elem_iterator; for ( global_elem_iterator = global_elements.begin(); global_elem_iterator != global_elements.end(); ++global_elem_iterator ) { // Get the individual element vertices. error = d_moab->get_adjacencies( &*global_elem_iterator, 1, 0, false, elem_vertices ); assert( error == moab::MB_SUCCESS ); // Get the invidivual element coordinates. error = d_moab->get_coords( &elem_vertices[0], elem_vertices.size(), &elem_coords[0] ); assert( error == moab::MB_SUCCESS ); // Partition in x direction. if ( partitioning_type == 0 ) { for ( int i = 0; i < comm_size; ++i ) { if ( elem_coords[0] >= min + width*(comm_rank)/comm_size - 1e-6 && elem_coords[0] <= min + width*(comm_rank+1)/comm_size + 1e-6 ) { elements.push_back( *global_elem_iterator ); } } } // Partition in y direction. else if ( partitioning_type == 1 ) { for ( int i = 0; i < comm_size; ++i ) { if ( elem_coords[1] >= min + width*(comm_rank)/comm_size - 1e-6 && elem_coords[1] <= min + width*(comm_rank+1)/comm_size + 1e-6 ) { elements.push_back( *global_elem_iterator ); } } } else { throw std::logic_error( "Partitioning type not supported." ); } } Teuchos::ArrayRCP<moab::EntityHandle> elements_arcp( elements.size() ); std::copy( elements.begin(), elements.end(), elements_arcp.begin() ); elements.clear(); d_comm->barrier(); // Get the nodes. std::vector<moab::EntityHandle> vertices; error = d_moab->get_connectivity( &elements_arcp[0], elements_arcp.size(), vertices ); assert( error == moab::MB_SUCCESS ); d_vertices = Teuchos::ArrayRCP<moab::EntityHandle>( vertices.size() ); std::copy( vertices.begin(), vertices.end(), d_vertices.begin() ); vertices.clear(); // Get the node coordinates. Teuchos::ArrayRCP<double> coords( node_dim * d_vertices.size() ); std::vector<double> interleaved_coords( 3*d_vertices.size() ); error = d_moab->get_coords( &d_vertices[0], d_vertices.size(), &interleaved_coords[0] ); assert( error == moab::MB_SUCCESS ); for ( int n = 0; n < (int) d_vertices.size(); ++n ) { for ( int d = 0; d < (int) node_dim; ++d ) { coords[ d*d_vertices.size() + n ] = interleaved_coords[ n*3 + d ]; } } interleaved_coords.clear(); // Get the connectivity. int connectivity_size = elements_arcp.size() * nodes_per_element; Teuchos::ArrayRCP<moab::EntityHandle> connectivity( connectivity_size ); std::vector<moab::EntityHandle> elem_conn; for ( int i = 0; i < (int) elements_arcp.size(); ++i ) { error = d_moab->get_connectivity( &elements_arcp[i], 1, elem_conn ); assert( error == moab::MB_SUCCESS ); assert( elem_conn.size() == Teuchos::as<std::vector<moab::EntityHandle>::size_type>(nodes_per_element) ); for ( int n = 0; n < (int) elem_conn.size(); ++n ) { connectivity[ n*elements_arcp.size() + i ] = elem_conn[n]; } } // Get the permutation vector. Teuchos::ArrayRCP<int> permutation_list( nodes_per_element ); for ( int i = 0; i < (int) nodes_per_element; ++i ) { permutation_list[i] = i; } // Create the mesh container. d_mesh_container = Teuchos::rcp( new Container( node_dim, d_vertices, coords, getTopology(block_topology), nodes_per_element, elements_arcp, connectivity, permutation_list ) ); }
void YPlus::execute() { Mesh& mesh = this->mesh(); // Geometry data const Field& coords = mesh.geometry_fields().coordinates(); const Uint nb_nodes = coords.size(); const Uint dim = coords.row_size(); // Velocity data const Field& velocity_field = common::find_component_recursively_with_tag<Field>(mesh, options().value<std::string>("velocity_tag")); const auto velocity_dict_handle = Handle<Dictionary const>(velocity_field.parent()); cf3_assert(velocity_dict_handle != nullptr); const Dictionary& velocity_dict = *velocity_dict_handle; const Uint vel_offset = velocity_field.descriptor().offset("Velocity"); // initialize if needed auto volume_node_connectivity = Handle<NodeConnectivity>(mesh.get_child("volume_node_connectivity")); if(m_normals.empty()) { // Node-to-element connectivity for the volume elements volume_node_connectivity = mesh.create_component<NodeConnectivity>("volume_node_connectivity"); std::vector< Handle<Entities const> > volume_entities; for(const mesh::Elements& elements : common::find_components_recursively_with_filter<mesh::Elements>(mesh, IsElementsVolume())) { volume_entities.push_back(elements.handle<Entities const>()); } volume_node_connectivity->initialize(nb_nodes, volume_entities); mesh.geometry_fields().create_field("wall_velocity_gradient_nodal").add_tag("wall_velocity_gradient_nodal"); Dictionary& wall_P0 = *mesh.create_component<DiscontinuousDictionary>("wall_P0"); m_normals.clear(); for(const Handle<Region>& region : regions()) { for(mesh::Elements& wall_entity : common::find_components_recursively_with_filter<mesh::Elements>(*region, IsElementsSurface())) { const Uint nb_elems = wall_entity.size(); const auto& geom_conn = wall_entity.geometry_space().connectivity(); const ElementType& etype = wall_entity.element_type(); const Uint element_nb_nodes = etype.nb_nodes(); m_normals.push_back(std::vector<RealVector>(nb_elems, RealVector(dim))); RealMatrix elem_coords(element_nb_nodes, dim); for(Uint elem_idx = 0; elem_idx != nb_elems; ++elem_idx) { const Connectivity::ConstRow conn_row = geom_conn[elem_idx]; fill(elem_coords, coords, conn_row); RealVector normal(dim); etype.compute_normal(elem_coords, m_normals.back()[elem_idx]); m_normals.back()[elem_idx] /= m_normals.back()[elem_idx].norm(); } wall_entity.create_component<FaceConnectivity>("wall_face_connectivity")->initialize(*volume_node_connectivity); wall_entity.create_space("cf3.mesh.LagrangeP0."+wall_entity.element_type().shape_name(),wall_P0); } } wall_P0.build(); // to tell the dictionary that all spaces have been added mesh.update_structures(); // to tell the mesh there is a new dictionary added manually wall_P0.create_field("wall_velocity_gradient").add_tag("wall_velocity_gradient"); } // Create the y+ field in the geometry dictionary if(common::find_component_ptr_with_tag(mesh.geometry_fields(), "yplus") == nullptr) { mesh.geometry_fields().create_field("yplus").add_tag("yplus"); } // Compute shear stress Uint surface_idx = 0; Dictionary& wall_P0 = *Handle<mesh::Dictionary>(mesh.get_child_checked("wall_P0")); Field& wall_velocity_gradient_field = *Handle<Field>(wall_P0.get_child_checked("wall_velocity_gradient")); for(const Handle<Region>& region : regions()) { for(const mesh::Elements& elements : common::find_components_recursively_with_filter<mesh::Elements>(*region, IsElementsSurface())) { const Uint nb_elements = elements.geometry_space().connectivity().size(); cf3_assert(elements.element_type().nb_faces() == 1); const auto& face_connectivity = *Handle<FaceConnectivity const>(elements.get_child_checked("wall_face_connectivity")); const auto& wall_conn = elements.space(wall_P0).connectivity(); for(Uint surface_elm_idx = 0; surface_elm_idx != nb_elements; ++surface_elm_idx) { if(face_connectivity.has_adjacent_element(surface_elm_idx, 0)) { const Uint wall_field_idx = wall_conn[surface_elm_idx][0]; // Get the wall normal vector const RealVector& normal = m_normals[surface_idx][surface_elm_idx]; RealVector3 normal3; normal3[0] = normal[0]; normal3[1] = normal[1]; normal3[2] = dim == 3 ? normal[2] : 0.; // The connected volume element NodeConnectivity::ElementReferenceT connected = face_connectivity.adjacent_element(surface_elm_idx, 0); const mesh::Entities& volume_entities = *face_connectivity.node_connectivity().entities()[connected.first]; const Uint volume_elem_idx = connected.second; const auto& velocity_conn = volume_entities.space(velocity_dict).connectivity(); const auto& velocity_sf = volume_entities.space(velocity_dict).shape_function(); const auto& geom_conn = volume_entities.geometry_space().connectivity(); const ElementType& volume_etype = volume_entities.element_type(); const Uint nb_vel_nodes = velocity_sf.nb_nodes(); const RealVector centroid_mapped_coord = 0.5*(velocity_sf.local_coordinates().colwise().minCoeff() + velocity_sf.local_coordinates().colwise().maxCoeff()); RealMatrix elem_coords(geom_conn.row_size(), dim); fill(elem_coords, coords, geom_conn[volume_elem_idx]); RealVector tangential_velocity(nb_vel_nodes); // For every node, the component of the velocity tangential to the wall RealVector3 v3; for(Uint i = 0; i != nb_vel_nodes; ++i) { Eigen::Map<RealVector const> v(&velocity_field[velocity_conn[volume_elem_idx][i]][vel_offset], dim); v3[0] = v[0]; v3[1] = v[1]; v3[2] = dim == 3 ? v[2] : 0.; tangential_velocity[i] = v3.cross(normal3).norm(); } wall_velocity_gradient_field[wall_field_idx][0] = fabs((volume_etype.jacobian(centroid_mapped_coord, elem_coords).inverse() * velocity_sf.gradient(centroid_mapped_coord) * tangential_velocity).dot(-normal)); } } ++surface_idx; } } wall_velocity_gradient_field.synchronize(); // Compute a nodal version of the wall velocity gradient const auto& wall_node_connectivity = *Handle<NodeConnectivity>(mesh.get_child_checked("wall_node_connectivity")); Field& wall_velocity_gradient_field_nodal = *Handle<Field>(mesh.geometry_fields().get_child_checked("wall_velocity_gradient_nodal")); for(Uint node_idx = 0; node_idx != nb_nodes; ++node_idx) { Uint nb_connected_elems = 0; wall_velocity_gradient_field_nodal[node_idx][0] = 0; for(const NodeConnectivity::ElementReferenceT elref : wall_node_connectivity.node_element_range(node_idx)) { const Uint wall_field_idx = wall_node_connectivity.entities()[elref.first]->space(wall_P0).connectivity()[elref.second][0]; wall_velocity_gradient_field_nodal[node_idx][0] += wall_velocity_gradient_field[wall_field_idx][0]; ++nb_connected_elems; } if(nb_connected_elems != 0) { wall_velocity_gradient_field_nodal[node_idx][0] /= static_cast<Real>(nb_connected_elems); } } // Set Yplus Field& yplus_field = *Handle<Field>(mesh.geometry_fields().get_child_checked("yplus")); const Field& wall_distance_field = *Handle<Field>(mesh.geometry_fields().get_child_checked("wall_distance")); const auto& node_to_wall_element = *Handle<common::Table<Uint>>(mesh.get_child_checked("node_to_wall_element")); const Real nu = physical_model().options().value<Real>("kinematic_viscosity"); for(Uint node_idx = 0; node_idx != nb_nodes; ++node_idx) { yplus_field[node_idx][0] = 0; if(node_to_wall_element[node_idx][0] != 0) { const Entities& wall_entities = *wall_node_connectivity.entities()[node_to_wall_element[node_idx][1]]; const Uint wall_field_idx = wall_entities.space(wall_P0).connectivity()[node_to_wall_element[node_idx][2]][0]; yplus_field[node_idx][0] = wall_distance_field[node_idx][0] * sqrt(nu*wall_velocity_gradient_field[wall_field_idx][0]) / nu; } else { yplus_field[node_idx][0] = wall_distance_field[node_idx][0] * sqrt(nu*wall_velocity_gradient_field_nodal[node_to_wall_element[node_idx][1]][0]) / nu; } } }