Exemplo n.º 1
0
/*
 * \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 ) );
}
Exemplo n.º 2
0
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;
    }
  }
}