Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
moab::HigherOrderFactory Class Reference

Functions for converting to/from higher-order elements. More...

#include <HigherOrderFactory.hpp>

+ Collaboration diagram for moab::HigherOrderFactory:

Public Member Functions

 HigherOrderFactory (Core *, Interface::HONodeAddedRemoved *function_object)
 ~HigherOrderFactory ()
ErrorCode convert (const EntityHandle meshset, const bool mid_edge_nodes, const bool mid_face_nodes, const bool mid_volume_nodes)
ErrorCode convert (const Range &entities, const bool mid_edge_nodes, const bool mid_face_nodes, const bool mid_volume_nodes)

Public Attributes

unsigned char mNodeMap [MBMAXTYPE][8][8]

Private Member Functions

void initialize_map ()
ErrorCode convert_sequence (ElementSequence *sequence, EntityHandle sequence_subset_start, EntityHandle sequence_subset_end, bool mid_edge_nodes, bool mid_face_nodes, bool mid_volume_nodes)
ErrorCode add_mid_edge_nodes (ElementSequence *)
ErrorCode add_mid_face_nodes (ElementSequence *)
ErrorCode add_mid_volume_nodes (ElementSequence *)
EntityHandle center_node_exist (EntityHandle corner1, EntityHandle corner2, std::vector< EntityHandle > &adj_entities)
 returns the handle of the first center node found between the two corner nodes. returns zero if none found entities that share those two corner nodes and have space allocated for mid-edge nodes are returned in a vector
EntityHandle center_node_exist (EntityHandle corners[4], std::vector< EntityHandle > &adj_entities)
 returns the handle of the first center node found between the 3-4 corner nodes. set the last node to zero if you want only 3 nodes returns zero if none found entities that share those corner nodes and have space allocated for mid face nodes are returned in a vector
bool add_center_node (EntityType type, EntityHandle *element_conn, int conn_size, EntityHandle corner_node1, EntityHandle corner_node2, EntityHandle center_node)
 adds a center node to element between corner nodes, returns success
ErrorCode copy_corner_nodes (ElementSequence *src, ElementSequence *dst)
ErrorCode copy_mid_edge_nodes (ElementSequence *src, ElementSequence *dst)
ErrorCode copy_mid_face_nodes (ElementSequence *src, ElementSequence *dst)
ErrorCode copy_mid_volume_nodes (ElementSequence *src, ElementSequence *dst)
ErrorCode copy_nodes (ElementSequence *src, ElementSequence *dst, unsigned nodes_per_elem_to_copy, unsigned src_conn_offset, unsigned dst_conn_offset)
ErrorCode zero_mid_edge_nodes (ElementSequence *dst)
ErrorCode zero_mid_face_nodes (ElementSequence *dst)
ErrorCode zero_mid_volume_nodes (ElementSequence *dst)
ErrorCode zero_nodes (ElementSequence *dst, unsigned nodes_per_elem_to_zero, unsigned dst_conn_offset)
ErrorCode remove_mid_edge_nodes (ElementSequence *seq, EntityHandle start, EntityHandle stop, Tag deletable_ndoes)
ErrorCode remove_mid_face_nodes (ElementSequence *seq, EntityHandle start, EntityHandle stop, Tag deletable_ndoes)
ErrorCode remove_mid_volume_nodes (ElementSequence *seq, EntityHandle start, EntityHandle stop, Tag deletable_ndoes)
ErrorCode remove_ho_nodes (ElementSequence *sequence, EntityHandle subset_start_handle, EntityHandle subset_end_handle, int nodes_per_elem_to_remove, int elem_conn_offset_to_remove, Tag deletable_nodes)
bool tag_for_deletion (EntityHandle element_with_node, int node_index_in_elem_connectivity, ElementSequence *sequence)

Private Attributes

CoremMB
Interface::HONodeAddedRemovedmHONodeAddedRemoved

Detailed Description

Functions for converting to/from higher-order elements.

Authors:
Clinton Stimpson
Date:
11/25/02

Definition at line 38 of file HigherOrderFactory.hpp.


Constructor & Destructor Documentation

Definition at line 39 of file HigherOrderFactory.cpp.

References initialize_map().

    : mMB( MB ), mHONodeAddedRemoved( function_object )
{
    initialize_map();
}

Member Function Documentation

bool moab::HigherOrderFactory::add_center_node ( EntityType  type,
EntityHandle element_conn,
int  conn_size,
EntityHandle  corner_node1,
EntityHandle  corner_node2,
EntityHandle  center_node 
) [private]

adds a center node to element between corner nodes, returns success

Definition at line 597 of file HigherOrderFactory.cpp.

References mNodeMap.

{
    int first_node  = std::find( element_conn, element_conn + conn_size, corner_node1 ) - element_conn;
    int second_node = std::find( element_conn, element_conn + conn_size, corner_node2 ) - element_conn;
    if( first_node == conn_size || second_node == conn_size )
        assert( "We should always find our nodes no matter what" == NULL );
    int high_node_index           = mNodeMap[this_type][first_node][second_node];
    element_conn[high_node_index] = center_node;
    return true;
}

Definition at line 387 of file HigherOrderFactory.cpp.

References center_node_exist(), moab::CN::ConnMap::conn, moab::Core::create_vertex(), moab::SequenceManager::find(), moab::ElementSequence::get_connectivity_array(), MB_SUCCESS, moab::CN::mConnectivityMap, mHONodeAddedRemoved, mMB, moab::Interface::HONodeAddedRemoved::node_added(), moab::ElementSequence::nodes_per_element(), moab::CN::ConnMap::num_sub_elements, moab::Core::sequence_manager(), moab::EntitySequence::size(), moab::EntitySequence::start_handle(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    // for each node, need to see if it was already created.
    EntityType this_type         = seq->type();
    SequenceManager* seq_manager = mMB->sequence_manager();

    // offset by number of corner nodes
    int num_vertices = CN::VerticesPerEntity( this_type );
    int num_edges    = CN::mConnectivityMap[this_type][0].num_sub_elements;

    const CN::ConnMap& entity_edges = CN::mConnectivityMap[this_type][0];

    EntityHandle* element     = seq->get_connectivity_array();
    EntityHandle curr_handle  = seq->start_handle();
    int nodes_per_element     = seq->nodes_per_element();
    EntityHandle* end_element = element + nodes_per_element * ( seq->size() );

    EntityHandle tmp_edge_conn[2];
    std::vector< EntityHandle > adjacent_entities( 32 );

    double tmp_coords[3];

    // iterate over the elements
    for( ; element < end_element; element += nodes_per_element )
    {
        // for each edge in this entity
        for( int i = 0; i < num_edges; i++ )
        {
            // a node was already assigned
            if( element[i + num_vertices] != 0 ) continue;

            tmp_edge_conn[0] = element[entity_edges.conn[i][0]];
            tmp_edge_conn[1] = element[entity_edges.conn[i][1]];

            EntityHandle already_made_node = center_node_exist( tmp_edge_conn[0], tmp_edge_conn[1], adjacent_entities );

            if( already_made_node )
            {
                element[i + num_vertices] = already_made_node;
            }
            // create a node
            else
            {
                EntitySequence* tmp_sequence = NULL;
                double sum_coords[3]         = { 0, 0, 0 };
                seq_manager->find( tmp_edge_conn[0], tmp_sequence );
                static_cast< VertexSequence* >( tmp_sequence )
                    ->get_coordinates( tmp_edge_conn[0], tmp_coords[0], tmp_coords[1], tmp_coords[2] );
                sum_coords[0] += tmp_coords[0];
                sum_coords[1] += tmp_coords[1];
                sum_coords[2] += tmp_coords[2];
                seq_manager->find( tmp_edge_conn[1], tmp_sequence );
                static_cast< VertexSequence* >( tmp_sequence )
                    ->get_coordinates( tmp_edge_conn[1], tmp_coords[0], tmp_coords[1], tmp_coords[2] );
                sum_coords[0] = ( sum_coords[0] + tmp_coords[0] ) / 2;
                sum_coords[1] = ( sum_coords[1] + tmp_coords[1] ) / 2;
                sum_coords[2] = ( sum_coords[2] + tmp_coords[2] ) / 2;

                mMB->create_vertex( sum_coords, element[i + num_vertices] );
            }

            if( mHONodeAddedRemoved ) mHONodeAddedRemoved->node_added( element[i + num_vertices], curr_handle );
        }

        curr_handle++;
    }

    return MB_SUCCESS;
}

Definition at line 310 of file HigherOrderFactory.cpp.

References center_node_exist(), moab::CN::ConnMap::conn, moab::Core::create_vertex(), moab::SequenceManager::find(), moab::ElementSequence::get_connectivity_array(), moab::ElementSequence::has_mid_edge_nodes(), MB_SUCCESS, moab::CN::mConnectivityMap, mHONodeAddedRemoved, mMB, moab::Interface::HONodeAddedRemoved::node_added(), moab::ElementSequence::nodes_per_element(), moab::CN::ConnMap::num_corners_per_sub_element, moab::CN::ConnMap::num_sub_elements, moab::Core::sequence_manager(), moab::EntitySequence::size(), moab::EntitySequence::start_handle(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    EntityType this_type         = seq->type();
    SequenceManager* seq_manager = mMB->sequence_manager();
    int num_vertices             = CN::VerticesPerEntity( this_type );
    int num_edges                = CN::mConnectivityMap[this_type][0].num_sub_elements;
    num_edges                    = seq->has_mid_edge_nodes() ? num_edges : 0;
    int num_faces                = CN::mConnectivityMap[this_type][1].num_sub_elements;

    const CN::ConnMap& entity_faces = CN::mConnectivityMap[this_type][1];

    EntityHandle* element     = seq->get_connectivity_array();
    EntityHandle curr_handle  = seq->start_handle();
    int nodes_per_element     = seq->nodes_per_element();
    EntityHandle* end_element = element + nodes_per_element * ( seq->size() );

    EntityHandle tmp_face_conn[4];  // max face nodes = 4
    std::vector< EntityHandle > adjacent_entities( 4 );

    double tmp_coords[3];

    // iterate over the elements
    for( ; element < end_element; element += nodes_per_element )
    {
        // for each edge in this entity
        for( int i = 0; i < num_faces; i++ )
        {
            // a node was already assigned
            if( element[i + num_edges + num_vertices] != 0 ) continue;

            tmp_face_conn[0] = element[entity_faces.conn[i][0]];
            tmp_face_conn[1] = element[entity_faces.conn[i][1]];
            tmp_face_conn[2] = element[entity_faces.conn[i][2]];
            if( entity_faces.num_corners_per_sub_element[i] == 4 )
                tmp_face_conn[3] = element[entity_faces.conn[i][3]];
            else
                tmp_face_conn[3] = 0;

            EntityHandle already_made_node = center_node_exist( tmp_face_conn, adjacent_entities );

            if( already_made_node )
            {
                element[i + num_edges + num_vertices] = already_made_node;
            }
            // create a node
            else
            {
                EntitySequence* tmp_sequence = NULL;
                double sum_coords[3]         = { 0, 0, 0 };
                int max_nodes                = entity_faces.num_corners_per_sub_element[i];
                for( int k = 0; k < max_nodes; k++ )
                {
                    seq_manager->find( tmp_face_conn[k], tmp_sequence );
                    static_cast< VertexSequence* >( tmp_sequence )
                        ->get_coordinates( tmp_face_conn[k], tmp_coords[0], tmp_coords[1], tmp_coords[2] );
                    sum_coords[0] += tmp_coords[0];
                    sum_coords[1] += tmp_coords[1];
                    sum_coords[2] += tmp_coords[2];
                }

                sum_coords[0] /= max_nodes;
                sum_coords[1] /= max_nodes;
                sum_coords[2] /= max_nodes;

                mMB->create_vertex( sum_coords, element[i + num_edges + num_vertices] );
            }

            if( mHONodeAddedRemoved )
                mHONodeAddedRemoved->node_added( element[i + num_edges + num_vertices], curr_handle );
        }

        curr_handle++;
    }

    return MB_SUCCESS;
}

Definition at line 261 of file HigherOrderFactory.cpp.

References moab::Core::create_vertex(), moab::SequenceManager::find(), moab::ElementSequence::get_connectivity_array(), moab::ElementSequence::has_mid_edge_nodes(), moab::ElementSequence::has_mid_face_nodes(), MB_SUCCESS, moab::CN::mConnectivityMap, mHONodeAddedRemoved, mMB, moab::Interface::HONodeAddedRemoved::node_added(), moab::ElementSequence::nodes_per_element(), moab::CN::ConnMap::num_sub_elements, moab::Core::sequence_manager(), moab::EntitySequence::size(), moab::EntitySequence::start_handle(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    EntityType this_type         = seq->type();
    SequenceManager* seq_manager = mMB->sequence_manager();

    // find out where in the connectivity list to add these new mid volume nodes
    int edge_factor = seq->has_mid_edge_nodes() ? 1 : 0;
    int face_factor = seq->has_mid_face_nodes() ? 1 : 0;
    // offset by number of higher order nodes on edges if they exist
    int num_corner_nodes = CN::VerticesPerEntity( this_type );
    int new_node_index   = num_corner_nodes;
    new_node_index += edge_factor * CN::mConnectivityMap[this_type][0].num_sub_elements;
    new_node_index += face_factor * CN::mConnectivityMap[this_type][1].num_sub_elements;

    EntityHandle* element     = seq->get_connectivity_array();
    EntityHandle curr_handle  = seq->start_handle();
    int nodes_per_element     = seq->nodes_per_element();
    EntityHandle* end_element = element + nodes_per_element * ( seq->size() );

    // iterate over the elements
    for( ; element < end_element; element += nodes_per_element )
    {
        // find the centroid of this element
        double tmp_coords[3], sum_coords[3] = { 0, 0, 0 };
        EntitySequence* eseq = NULL;
        for( int i = 0; i < num_corner_nodes; i++ )
        {
            seq_manager->find( element[i], eseq );
            static_cast< VertexSequence* >( eseq )->get_coordinates( element[i], tmp_coords[0], tmp_coords[1],
                                                                     tmp_coords[2] );
            sum_coords[0] += tmp_coords[0];
            sum_coords[1] += tmp_coords[1];
            sum_coords[2] += tmp_coords[2];
        }
        sum_coords[0] /= num_corner_nodes;
        sum_coords[1] /= num_corner_nodes;
        sum_coords[2] /= num_corner_nodes;

        // create a new vertex at the centroid
        mMB->create_vertex( sum_coords, element[new_node_index] );

        if( mHONodeAddedRemoved ) mHONodeAddedRemoved->node_added( element[new_node_index], curr_handle );

        curr_handle++;
    }

    return MB_SUCCESS;
}
EntityHandle moab::HigherOrderFactory::center_node_exist ( EntityHandle  corner1,
EntityHandle  corner2,
std::vector< EntityHandle > &  adj_entities 
) [private]

returns the handle of the first center node found between the two corner nodes. returns zero if none found entities that share those two corner nodes and have space allocated for mid-edge nodes are returned in a vector

Definition at line 457 of file HigherOrderFactory.cpp.

References moab::Core::a_entity_factory(), moab::AEntityFactory::create_vert_elem_adjacencies(), moab::AEntityFactory::get_adjacencies(), moab::Core::get_connectivity(), moab::CN::HasMidEdgeNodes(), MBENTITYSET, mMB, mNodeMap, moab::TYPE_FROM_HANDLE(), and moab::AEntityFactory::vert_elem_adjacencies().

Referenced by add_mid_edge_nodes(), and add_mid_face_nodes().

{
    AEntityFactory* a_fact = mMB->a_entity_factory();
    std::vector< EntityHandle > adj_corner1( 32 );
    std::vector< EntityHandle > adj_corner2( 32 );

    // create needed vertex adjacencies
    if( !a_fact->vert_elem_adjacencies() ) a_fact->create_vert_elem_adjacencies();

    // vectors are returned sorted

    a_fact->get_adjacencies( corner1, adj_corner1 );
    a_fact->get_adjacencies( corner2, adj_corner2 );

    // these are the entities adjacent to both nodes
    adj_entities.clear();
    std::set_intersection( adj_corner1.begin(), adj_corner1.end(), adj_corner2.begin(), adj_corner2.end(),
                           std::back_inserter< std::vector< EntityHandle > >( adj_entities ) );

    // iterate of the entities to find a mid node
    const EntityHandle* conn;
    int conn_size = 0;
    for( std::vector< EntityHandle >::iterator iter = adj_entities.begin(); iter != adj_entities.end(); )
    {
        EntityType this_type = TYPE_FROM_HANDLE( *iter );
        if( this_type == MBENTITYSET )
        {
            ++iter;
            continue;
        }
        mMB->get_connectivity( *iter, conn, conn_size );
        // if this entity has mid edge nodes
        if( CN::HasMidEdgeNodes( this_type, conn_size ) )
        {
            // find out at which index the mid node should be at
            int first_node  = std::find( conn, conn + conn_size, corner1 ) - conn;
            int second_node = std::find( conn, conn + conn_size, corner2 ) - conn;
            if( first_node == conn_size || second_node == conn_size )
                assert( "We should always find our nodes no matter what" == NULL );
            int high_node_index = mNodeMap[this_type][first_node][second_node];
            if( conn[high_node_index] != 0 ) return conn[high_node_index];
            ++iter;
        }
        else
        {
            iter = adj_entities.erase( iter );
        }
    }

    return 0;
}
EntityHandle moab::HigherOrderFactory::center_node_exist ( EntityHandle  corners[4],
std::vector< EntityHandle > &  adj_entities 
) [private]

returns the handle of the first center node found between the 3-4 corner nodes. set the last node to zero if you want only 3 nodes returns zero if none found entities that share those corner nodes and have space allocated for mid face nodes are returned in a vector

Definition at line 511 of file HigherOrderFactory.cpp.

References moab::Core::a_entity_factory(), moab::CN::ConnMap::conn, moab::AEntityFactory::create_vert_elem_adjacencies(), moab::AEntityFactory::get_adjacencies(), moab::Core::get_connectivity(), moab::CN::HasMidEdgeNodes(), moab::CN::HasMidFaceNodes(), MBENTITYSET, moab::CN::mConnectivityMap, mMB, moab::CN::ConnMap::num_sub_elements, moab::CN::ConnMap::target_type, moab::TYPE_FROM_HANDLE(), moab::AEntityFactory::vert_elem_adjacencies(), and moab::CN::VerticesPerEntity().

{
    AEntityFactory* a_fact = mMB->a_entity_factory();
    std::vector< EntityHandle > adj_corner[4];
    int num_nodes = corners[3] == 0 ? 3 : 4;
    int i         = 0;

    // create needed vertex adjacencies
    if( !a_fact->vert_elem_adjacencies() ) a_fact->create_vert_elem_adjacencies();

    // vectors are returned sorted
    for( i = 0; i < num_nodes; i++ )
        a_fact->get_adjacencies( corners[i], adj_corner[i] );

    // these are the entities adjacent to both nodes
    for( i = 1; i < num_nodes; i++ )
    {
        adj_entities.clear();
        std::set_intersection( adj_corner[i - 1].begin(), adj_corner[i - 1].end(), adj_corner[i].begin(),
                               adj_corner[i].end(), std::back_inserter< std::vector< EntityHandle > >( adj_entities ) );
        adj_corner[i].swap( adj_entities );
    }
    adj_entities.swap( adj_corner[i - 1] );

    // iterate of the entities to find a mid node
    const EntityHandle* conn;
    int conn_size = 0;
    for( std::vector< EntityHandle >::iterator iter = adj_entities.begin(); iter != adj_entities.end(); )
    {
        EntityType this_type = TYPE_FROM_HANDLE( *iter );
        if( this_type == MBENTITYSET )
        {
            ++iter;
            continue;
        }
        const CN::ConnMap& entity_faces = CN::mConnectivityMap[this_type][1];
        mMB->get_connectivity( *iter, conn, conn_size );
        int offset = CN::VerticesPerEntity( this_type );
        if( CN::HasMidEdgeNodes( this_type, conn_size ) ) offset += CN::mConnectivityMap[this_type][0].num_sub_elements;

        // if this entity has mid face nodes
        if( CN::HasMidFaceNodes( this_type, conn_size ) )
        {
            int k;
            int indexes[4];
            for( k = 0; k < num_nodes; k++ )
                indexes[k] = std::find( conn, conn + conn_size, corners[k] ) - conn;

            // find out at which index the mid node should be at
            for( k = 0; k < entity_faces.num_sub_elements; k++ )
            {
                if( CN::VerticesPerEntity( entity_faces.target_type[k] ) != num_nodes ) continue;

                int* pivot = std::find( indexes, indexes + num_nodes, entity_faces.conn[k][0] );
                if( pivot == indexes + num_nodes ) continue;

                if( pivot != indexes ) std::rotate( indexes, pivot, indexes + num_nodes );

                if( std::equal( indexes, indexes + num_nodes, entity_faces.conn[k] ) )
                {
                    if( conn[k + offset] != 0 ) return conn[k + offset];
                    k = entity_faces.num_sub_elements;
                }
                else
                {
                    int temp               = indexes[1];
                    indexes[1]             = indexes[num_nodes - 1];
                    indexes[num_nodes - 1] = temp;
                    if( std::equal( indexes, indexes + num_nodes, entity_faces.conn[k] ) )
                    {
                        if( conn[k + offset] != 0 ) return conn[k + offset];
                        k = entity_faces.num_sub_elements;
                    }
                }
            }
            ++iter;
        }
        else
        {
            iter = adj_entities.erase( iter );
        }
    }

    return 0;
}
ErrorCode moab::HigherOrderFactory::convert ( const EntityHandle  meshset,
const bool  mid_edge_nodes,
const bool  mid_face_nodes,
const bool  mid_volume_nodes 
)

Definition at line 71 of file HigherOrderFactory.cpp.

References entities, moab::Core::get_entities_by_handle(), and mMB.

Referenced by moab::Core::convert_entities(), and moab::Tqdcfr::read_block().

{
    Range entities;
    mMB->get_entities_by_handle( meshset, entities, true );
    return convert( entities, mid_edge_nodes, mid_face_nodes, mid_volume_nodes );
}
ErrorCode moab::HigherOrderFactory::convert ( const Range entities,
const bool  mid_edge_nodes,
const bool  mid_face_nodes,
const bool  mid_volume_nodes 
)

Definition at line 81 of file HigherOrderFactory.cpp.

References moab::Range::const_pair_begin(), moab::Range::const_pair_end(), convert_sequence(), moab::EntitySequence::end_handle(), ErrorCode, moab::SequenceManager::find(), moab::ElementSequence::get_connectivity_array(), MB_NOT_IMPLEMENTED, MB_SUCCESS, MB_TYPE_OUT_OF_RANGE, MBENTITYSET, MBVERTEX, mMB, moab::Core::sequence_manager(), and moab::EntitySequence::type().

{

    // TODO --  add some more code to prevent from splitting of entity sequences when we don't need
    // to. Say we have all hex8's in our mesh and 3 falses are passed in.  In the end, no conversion
    // will happen, but the sequences could still be split up.

    // find out what entity sequences we need to convert
    // and where, if necessary, to split them

    SequenceManager* seq_manager = mMB->sequence_manager();
    Range::const_pair_iterator p_iter;
    for( p_iter = entities.const_pair_begin(); p_iter != entities.const_pair_end(); ++p_iter )
    {

        EntityHandle h = p_iter->first;
        while( h <= p_iter->second )
        {

            EntitySequence* seq;
            ErrorCode rval = seq_manager->find( h, seq );
            if( MB_SUCCESS != rval ) return rval;

            if( seq->type() == MBVERTEX || seq->type() >= MBENTITYSET ) return MB_TYPE_OUT_OF_RANGE;

            // make sequence is not structured mesh
            ElementSequence* elemseq = static_cast< ElementSequence* >( seq );
            if( NULL == elemseq->get_connectivity_array() ) return MB_NOT_IMPLEMENTED;

            EntityHandle last = p_iter->second;
            if( last > seq->end_handle() ) last = seq->end_handle();

            rval = convert_sequence( elemseq, h, last, mid_edge_nodes, mid_face_nodes, mid_volume_nodes );
            if( MB_SUCCESS != rval ) return rval;

            h = last + 1;
        }
    }

    return MB_SUCCESS;
}
ErrorCode moab::HigherOrderFactory::convert_sequence ( ElementSequence sequence,
EntityHandle  sequence_subset_start,
EntityHandle  sequence_subset_end,
bool  mid_edge_nodes,
bool  mid_face_nodes,
bool  mid_volume_nodes 
) [private]

Definition at line 127 of file HigherOrderFactory.cpp.

References add_mid_edge_nodes(), add_mid_face_nodes(), add_mid_volume_nodes(), moab::Range::begin(), copy_corner_nodes(), copy_mid_edge_nodes(), copy_mid_face_nodes(), copy_mid_volume_nodes(), moab::EntitySequence::data(), moab::Core::delete_entities(), moab::CN::Dimension(), moab::Range::end(), ErrorCode, moab::Core::get_entities_by_type_and_tag(), moab::ElementSequence::has_mid_edge_nodes(), moab::ElementSequence::has_mid_face_nodes(), moab::ElementSequence::has_mid_volume_nodes(), MB_SUCCESS, MB_TAG_BIT, MB_TAG_CREAT, MB_TYPE_BIT, MB_TYPE_OUT_OF_RANGE, MBEDGE, MBHEX, MBKNIFE, MBPRISM, MBPYRAMID, MBQUAD, MBTET, MBTRI, MBVERTEX, mHONodeAddedRemoved, mMB, moab::Interface::HONodeAddedRemoved::node_removed(), moab::ElementSequence::nodes_per_element(), moab::CN::NumSubEntities(), remove_mid_edge_nodes(), remove_mid_face_nodes(), remove_mid_volume_nodes(), moab::SequenceManager::replace_subsequence(), moab::Core::sequence_manager(), moab::Core::tag_delete(), moab::Core::tag_get_data(), moab::Core::tag_get_handle(), moab::EntitySequence::type(), moab::CN::VerticesPerEntity(), zero_mid_edge_nodes(), zero_mid_face_nodes(), and zero_mid_volume_nodes().

Referenced by convert().

{

    ErrorCode status = MB_SUCCESS;

    // lets make sure parameters are ok before we continue
    switch( seq->type() )
    {
        default:
            return MB_TYPE_OUT_OF_RANGE;
        case MBEDGE:
            mid_face_nodes   = false;
            mid_volume_nodes = false;
            break;
        case MBTRI:
        case MBQUAD:
            mid_volume_nodes = false;
            break;
        case MBTET:
        case MBHEX:
        case MBPRISM:
        case MBPYRAMID:
        case MBKNIFE:
            break;
    }

    // calculate number of nodes in target configuration
    unsigned nodes_per_elem = CN::VerticesPerEntity( seq->type() );
    if( mid_edge_nodes ) nodes_per_elem += ( seq->type() == MBEDGE ) ? 1 : CN::NumSubEntities( seq->type(), 1 );
    if( mid_face_nodes )
        nodes_per_elem += ( CN::Dimension( seq->type() ) == 2 ) ? 1 : CN::NumSubEntities( seq->type(), 2 );
    if( mid_volume_nodes ) nodes_per_elem += 1;

    if( nodes_per_elem == seq->nodes_per_element() ) return MB_SUCCESS;

    Tag deletable_nodes;
    status = mMB->tag_get_handle( 0, 1, MB_TYPE_BIT, deletable_nodes, MB_TAG_CREAT | MB_TAG_BIT );
    if( MB_SUCCESS != status ) return status;

    UnstructuredElemSeq* new_seq = new UnstructuredElemSeq( start, end - start + 1, nodes_per_elem, end - start + 1 );

    copy_corner_nodes( seq, new_seq );

    if( seq->has_mid_edge_nodes() && mid_edge_nodes )
        status = copy_mid_edge_nodes( seq, new_seq );
    else if( seq->has_mid_edge_nodes() && !mid_edge_nodes )
        status = remove_mid_edge_nodes( seq, start, end, deletable_nodes );
    else if( !seq->has_mid_edge_nodes() && mid_edge_nodes )
        status = zero_mid_edge_nodes( new_seq );
    if( MB_SUCCESS != status ) return status;

    if( seq->has_mid_face_nodes() && mid_face_nodes )
        status = copy_mid_face_nodes( seq, new_seq );
    else if( seq->has_mid_face_nodes() && !mid_face_nodes )
        status = remove_mid_face_nodes( seq, start, end, deletable_nodes );
    else if( !seq->has_mid_face_nodes() && mid_face_nodes )
        status = zero_mid_face_nodes( new_seq );
    if( MB_SUCCESS != status )
    {
        mMB->tag_delete( deletable_nodes );
        return status;
    }

    if( seq->has_mid_volume_nodes() && mid_volume_nodes )
        status = copy_mid_volume_nodes( seq, new_seq );
    else if( seq->has_mid_volume_nodes() && !mid_volume_nodes )
        status = remove_mid_volume_nodes( seq, start, end, deletable_nodes );
    else if( !seq->has_mid_volume_nodes() && mid_volume_nodes )
        status = zero_mid_volume_nodes( new_seq );
    if( MB_SUCCESS != status )
    {
        mMB->tag_delete( deletable_nodes );
        return status;
    }

    // gather nodes that were marked
    Range nodes;
    mMB->get_entities_by_type_and_tag( 0, MBVERTEX, &deletable_nodes, NULL, 1, nodes );

    // EntityHandle low_meshset;
    // int dum;
    // low_meshset = CREATE_HANDLE(MBENTITYSET, 0, dum);

    for( Range::iterator iter = nodes.begin(); iter != nodes.end(); ++iter )
    {
        unsigned char marked = 0;
        mMB->tag_get_data( deletable_nodes, &( *iter ), 1, &marked );
        if( marked )
        {
            // we can delete it
            if( mHONodeAddedRemoved ) mHONodeAddedRemoved->node_removed( *iter );
            mMB->delete_entities( &( *iter ), 1 );
        }
    }

    const bool create_midedge = !seq->has_mid_edge_nodes() && mid_edge_nodes;
    const bool create_midface = !seq->has_mid_face_nodes() && mid_face_nodes;
    const bool create_midvolm = !seq->has_mid_volume_nodes() && mid_volume_nodes;

    mMB->tag_delete( deletable_nodes );

    status = mMB->sequence_manager()->replace_subsequence( new_seq );
    if( MB_SUCCESS != status )
    {
        SequenceData* data = new_seq->data();
        delete new_seq;
        delete data;
        return status;
    }

    if( create_midedge )
    {
        status = add_mid_edge_nodes( new_seq );
        if( MB_SUCCESS != status ) return status;
    }
    if( create_midface )
    {
        status = add_mid_face_nodes( new_seq );
        if( MB_SUCCESS != status ) return status;
    }
    if( create_midvolm )
    {
        status = add_mid_volume_nodes( new_seq );
        if( MB_SUCCESS != status ) return status;
    }

    return status;
}

Definition at line 613 of file HigherOrderFactory.cpp.

References copy_nodes(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    unsigned num_corners = CN::VerticesPerEntity( src->type() );
    return copy_nodes( src, dst, num_corners, 0, 0 );
}

Definition at line 619 of file HigherOrderFactory.cpp.

References copy_nodes(), moab::ElementSequence::has_mid_edge_nodes(), MBEDGE, moab::CN::NumSubEntities(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    if( !src->has_mid_edge_nodes() || !dst->has_mid_edge_nodes() ) return MB_FAILURE;

    unsigned num_corners = CN::VerticesPerEntity( src->type() );
    unsigned num_edges   = ( src->type() == MBEDGE ) ? 1 : CN::NumSubEntities( src->type(), 1 );
    return copy_nodes( src, dst, num_edges, num_corners, num_corners );
}

Definition at line 637 of file HigherOrderFactory.cpp.

References copy_nodes(), moab::CN::Dimension(), moab::ElementSequence::has_mid_edge_nodes(), moab::ElementSequence::has_mid_face_nodes(), moab::CN::NumSubEntities(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    if( !src->has_mid_face_nodes() || !dst->has_mid_face_nodes() ) return MB_FAILURE;

    unsigned src_offset = CN::VerticesPerEntity( src->type() );
    unsigned dst_offset = src_offset;
    if( src->has_mid_edge_nodes() ) src_offset += CN::NumSubEntities( src->type(), 1 );
    if( dst->has_mid_edge_nodes() ) dst_offset += CN::NumSubEntities( dst->type(), 1 );
    unsigned num_faces = ( CN::Dimension( src->type() ) == 2 ) ? 1 : CN::NumSubEntities( src->type(), 2 );
    return copy_nodes( src, dst, num_faces, src_offset, dst_offset );
}

Definition at line 659 of file HigherOrderFactory.cpp.

References copy_nodes(), moab::ElementSequence::has_mid_edge_nodes(), moab::ElementSequence::has_mid_face_nodes(), moab::ElementSequence::has_mid_volume_nodes(), moab::CN::NumSubEntities(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    if( !src->has_mid_volume_nodes() || !dst->has_mid_volume_nodes() ) return MB_FAILURE;

    unsigned src_offset = CN::VerticesPerEntity( src->type() );
    unsigned dst_offset = src_offset;
    if( src->has_mid_edge_nodes() ) src_offset += CN::NumSubEntities( src->type(), 1 );
    if( dst->has_mid_edge_nodes() ) dst_offset += CN::NumSubEntities( dst->type(), 1 );
    if( src->has_mid_face_nodes() ) src_offset += CN::NumSubEntities( src->type(), 2 );
    if( dst->has_mid_face_nodes() ) dst_offset += CN::NumSubEntities( dst->type(), 2 );
    return copy_nodes( src, dst, 1, src_offset, dst_offset );
}
ErrorCode moab::HigherOrderFactory::copy_nodes ( ElementSequence src,
ElementSequence dst,
unsigned  nodes_per_elem_to_copy,
unsigned  src_conn_offset,
unsigned  dst_conn_offset 
) [private]

Definition at line 682 of file HigherOrderFactory.cpp.

References moab::EntitySequence::end_handle(), moab::ElementSequence::get_connectivity_array(), MB_SUCCESS, moab::ElementSequence::nodes_per_element(), moab::EntitySequence::size(), moab::EntitySequence::start_handle(), and moab::EntitySequence::type().

Referenced by copy_corner_nodes(), copy_mid_edge_nodes(), copy_mid_face_nodes(), and copy_mid_volume_nodes().

{
    if( src->type() != dst->type() ) return MB_FAILURE;

    unsigned src_stride    = src->nodes_per_element();
    unsigned dst_stride    = dst->nodes_per_element();
    EntityHandle* src_conn = src->get_connectivity_array();
    EntityHandle* dst_conn = dst->get_connectivity_array();
    if( !src_conn || !dst_conn ) return MB_FAILURE;

    if( dst->start_handle() < src->start_handle() || dst->end_handle() > src->end_handle() ) return MB_FAILURE;

    src_conn += ( dst->start_handle() - src->start_handle() ) * src_stride;
    EntityID count = dst->size();
    for( EntityID i = 0; i < count; ++i )
    {
        for( unsigned j = 0; j < nodes_per_elem; ++j )
            dst_conn[j + dst_offset] = src_conn[j + src_offset];
        src_conn += src_stride;
        dst_conn += dst_stride;
    }

    return MB_SUCCESS;
}

Definition at line 48 of file HigherOrderFactory.cpp.

References moab::CN::ConnMap::conn, MBMAXTYPE, MBVERTEX, moab::CN::mConnectivityMap, mNodeMap, moab::CN::ConnMap::num_sub_elements, and moab::CN::VerticesPerEntity().

Referenced by HigherOrderFactory().

{
    // if(mMapInitialized)
    //  return;

    for( EntityType i = MBVERTEX; i < MBMAXTYPE; i++ )
    {
        const CN::ConnMap& canon_map     = CN::mConnectivityMap[i][0];
        unsigned char( &this_map )[8][8] = mNodeMap[i];
        int num_node                     = CN::VerticesPerEntity( i );
        for( int j = 0; j < canon_map.num_sub_elements; j++ )
        {
            unsigned char x = canon_map.conn[j][0];
            unsigned char y = canon_map.conn[j][1];
            this_map[x][y]  = num_node;
            this_map[y][x]  = num_node;
            num_node++;
        }
    }

    // mMapInitialized = true;
}
ErrorCode moab::HigherOrderFactory::remove_ho_nodes ( ElementSequence seq,
EntityHandle  start,
EntityHandle  end,
int  nodes_per_elem,
int  elem_conn_offset,
Tag  deletable_nodes 
) [private]

MOAB, a Mesh-Oriented datABase, is a software component for creating, storing and accessing finite element mesh data.

Copyright 2004 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

Definition at line 794 of file HigherOrderFactory.cpp.

References moab::EntitySequence::end_handle(), moab::ElementSequence::get_connectivity_array(), MB_ENTITY_NOT_FOUND, MB_NOT_IMPLEMENTED, MB_SUCCESS, mMB, moab::ElementSequence::nodes_per_element(), moab::EntitySequence::start_handle(), tag_for_deletion(), and moab::Core::tag_set_data().

Referenced by remove_mid_edge_nodes(), remove_mid_face_nodes(), and remove_mid_volume_nodes().

{
    if( start < seq->start_handle() || end > seq->end_handle() ) return MB_ENTITY_NOT_FOUND;
    EntityHandle* array = seq->get_connectivity_array();
    if( !array ) return MB_NOT_IMPLEMENTED;

    std::set< EntityHandle > nodes_processed;
    for( EntityHandle i = start; i <= end; ++i )
    {  // for each element
        for( int j = 0; j < nodes_per_elem; ++j )
        {                                                        // for each HO node to remove
            const EntityID elem  = ( i - seq->start_handle() );  // element index
            const int conn_idx   = j + elem_conn_offset;
            const EntityID index = elem * seq->nodes_per_element() + conn_idx;
            if( array[index] && nodes_processed.insert( array[index] ).second )
            {
                if( tag_for_deletion( i, conn_idx, seq ) )
                {
                    unsigned char bit = 0x1;
                    mMB->tag_set_data( deletable_nodes, &( array[index] ), 1, &bit );
                }
            }
        }
    }

    return MB_SUCCESS;
}
ErrorCode moab::HigherOrderFactory::remove_mid_edge_nodes ( ElementSequence seq,
EntityHandle  start,
EntityHandle  stop,
Tag  deletable_ndoes 
) [private]

Definition at line 727 of file HigherOrderFactory.cpp.

References MBEDGE, moab::CN::NumSubEntities(), remove_ho_nodes(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    int count;
    int offset;
    if( seq->type() == MBEDGE )
    {
        count  = 1;
        offset = 2;
    }
    else
    {
        count  = CN::NumSubEntities( seq->type(), 1 );
        offset = CN::VerticesPerEntity( seq->type() );
    }

    return remove_ho_nodes( seq, start, end, count, offset, deletable_nodes );
}
ErrorCode moab::HigherOrderFactory::remove_mid_face_nodes ( ElementSequence seq,
EntityHandle  start,
EntityHandle  stop,
Tag  deletable_ndoes 
) [private]

Definition at line 748 of file HigherOrderFactory.cpp.

References moab::CN::Dimension(), moab::ElementSequence::has_mid_edge_nodes(), moab::CN::NumSubEntities(), remove_ho_nodes(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    int count;
    if( CN::Dimension( seq->type() ) == 2 )
        count = 1;
    else
        count = CN::NumSubEntities( seq->type(), 2 );
    int offset = CN::VerticesPerEntity( seq->type() );
    if( seq->has_mid_edge_nodes() ) offset += CN::NumSubEntities( seq->type(), 1 );

    return remove_ho_nodes( seq, start, end, count, offset, deletable_nodes );
}
ErrorCode moab::HigherOrderFactory::remove_mid_volume_nodes ( ElementSequence seq,
EntityHandle  start,
EntityHandle  stop,
Tag  deletable_ndoes 
) [private]

Definition at line 764 of file HigherOrderFactory.cpp.

References moab::ElementSequence::has_mid_edge_nodes(), moab::ElementSequence::has_mid_face_nodes(), moab::CN::NumSubEntities(), remove_ho_nodes(), moab::EntitySequence::type(), and moab::CN::VerticesPerEntity().

Referenced by convert_sequence().

{
    int offset = CN::VerticesPerEntity( seq->type() );
    if( seq->has_mid_edge_nodes() ) offset += CN::NumSubEntities( seq->type(), 1 );
    if( seq->has_mid_face_nodes() ) offset += CN::NumSubEntities( seq->type(), 2 );

    return remove_ho_nodes( seq, start, end, 1, offset, deletable_nodes );
}
bool moab::HigherOrderFactory::tag_for_deletion ( EntityHandle  element_with_node,
int  node_index_in_elem_connectivity,
ElementSequence sequence 
) [private]

Definition at line 827 of file HigherOrderFactory.cpp.

References moab::Core::a_entity_factory(), moab::CREATE_HANDLE(), moab::Core::dimension_from_handle(), moab::dum, moab::EntitySequence::end_handle(), ErrorCode, moab::AEntityFactory::get_adjacencies(), moab::Core::get_connectivity(), moab::CN::HONodeParent(), MB_CHK_ERR, MBENTITYSET, mMB, moab::ElementSequence::nodes_per_element(), moab::Core::side_element(), moab::side_number(), moab::EntitySequence::start_handle(), and moab::EntitySequence::type().

Referenced by remove_ho_nodes().

{
    // get type of this sequence
    EntityType this_type = seq->type();

    // get dimension of 'parent' element
    int this_dimension = mMB->dimension_from_handle( parent_handle );

    // tells us if higher order node is on
    int dimension, side_number;
    CN::HONodeParent( this_type, seq->nodes_per_element(), conn_index, dimension, side_number );

    // it MUST be a higher-order node
    bool delete_node = false;

    assert( dimension != -1 );
    assert( side_number != -1 );

    // could be a mid-volume/face/edge node on a hex/face/edge respectively
    // if so...delete it bc/ no one else owns it too
    std::vector< EntityHandle > connectivity;
    if( dimension == this_dimension && side_number == 0 )
        delete_node = true;
    else  // the node could also be on a lower order entity of 'tmp_entity'
    {
        // get 'side' of 'parent_handle' that node is on
        EntityHandle target_entity = 0;
        mMB->side_element( parent_handle, dimension, side_number, target_entity );

        if( target_entity )
        {
            AEntityFactory* a_fact = mMB->a_entity_factory();
            EntityHandle low_meshset;
            int dum;
            low_meshset = CREATE_HANDLE( MBENTITYSET, 0, dum );

            // just get corner nodes of target_entity
            connectivity.clear();
            ErrorCode rval;
            rval = mMB->get_connectivity( &( target_entity ), 1, connectivity, true );MB_CHK_ERR( rval );

            // for each node, get all common adjacencies of nodes in 'parent_handle'
            std::vector< EntityHandle > adj_list_1, adj_list_2, adj_entities;
            a_fact->get_adjacencies( connectivity[0], adj_list_1 );

            // remove meshsets
            adj_list_1.erase(
                std::remove_if( adj_list_1.begin(), adj_list_1.end(),
                                std::bind( std::greater< EntityHandle >(), std::placeholders::_1, low_meshset ) ),
                adj_list_1.end() );
            // std::bind2nd(std::greater<EntityHandle>(),low_meshset)), adj_list_1.end());
            // https://stackoverflow.com/questions/32739018/a-replacement-for-stdbind2nd

            size_t i;
            for( i = 1; i < connectivity.size(); i++ )
            {
                adj_list_2.clear();
                a_fact->get_adjacencies( connectivity[i], adj_list_2 );

                // remove meshsets
                adj_list_2.erase(
                    std::remove_if( adj_list_2.begin(), adj_list_2.end(),
                                    std::bind( std::greater< EntityHandle >(), std::placeholders::_1, low_meshset ) ),
                    adj_list_2.end() );
                // std::bind2nd(std::greater<EntityHandle>(),low_meshset)), adj_list_2.end());
                // https://stackoverflow.com/questions/32739018/a-replacement-for-stdbind2nd

                // intersect the 2 lists
                adj_entities.clear();
                std::set_intersection( adj_list_1.begin(), adj_list_1.end(), adj_list_2.begin(), adj_list_2.end(),
                                       std::back_inserter< std::vector< EntityHandle > >( adj_entities ) );
                adj_list_1.clear();
                adj_list_1 = adj_entities;
            }

            assert( adj_entities.size() );  // has to have at least one adjacency

            // see if node is in other elements, not in this sequence...if so, delete it
            for( i = 0; i < adj_entities.size(); i++ )
            {
                if( adj_entities[i] >= seq->start_handle() && adj_entities[i] <= seq->end_handle() )
                {
                    delete_node = false;
                    break;
                }
                else
                    delete_node = true;
            }
        }
        else  // there is no lower order entity that also contains node
            delete_node = true;
    }

    return delete_node;
}

Definition at line 628 of file HigherOrderFactory.cpp.

References moab::ElementSequence::has_mid_edge_nodes(), MBEDGE, moab::CN::NumSubEntities(), moab::EntitySequence::type(), moab::CN::VerticesPerEntity(), and zero_nodes().

Referenced by convert_sequence().

{
    if( !dst->has_mid_edge_nodes() ) return MB_FAILURE;

    unsigned num_corners = CN::VerticesPerEntity( dst->type() );
    unsigned num_edges   = ( dst->type() == MBEDGE ) ? 1 : CN::NumSubEntities( dst->type(), 1 );
    return zero_nodes( dst, num_edges, num_corners );
}

Definition at line 649 of file HigherOrderFactory.cpp.

References moab::CN::Dimension(), moab::ElementSequence::has_mid_edge_nodes(), moab::ElementSequence::has_mid_face_nodes(), moab::CN::NumSubEntities(), moab::EntitySequence::type(), moab::CN::VerticesPerEntity(), and zero_nodes().

Referenced by convert_sequence().

{
    if( !dst->has_mid_face_nodes() ) return MB_FAILURE;

    unsigned dst_offset = CN::VerticesPerEntity( dst->type() );
    if( dst->has_mid_edge_nodes() ) dst_offset += CN::NumSubEntities( dst->type(), 1 );
    unsigned num_faces = ( CN::Dimension( dst->type() ) == 2 ) ? 1 : CN::NumSubEntities( dst->type(), 2 );
    return zero_nodes( dst, num_faces, dst_offset );
}

Definition at line 672 of file HigherOrderFactory.cpp.

References moab::ElementSequence::has_mid_edge_nodes(), moab::ElementSequence::has_mid_face_nodes(), moab::ElementSequence::has_mid_volume_nodes(), moab::CN::NumSubEntities(), moab::EntitySequence::type(), moab::CN::VerticesPerEntity(), and zero_nodes().

Referenced by convert_sequence().

{
    if( !dst->has_mid_volume_nodes() ) return MB_FAILURE;

    unsigned dst_offset = CN::VerticesPerEntity( dst->type() );
    if( dst->has_mid_edge_nodes() ) dst_offset += CN::NumSubEntities( dst->type(), 1 );
    if( dst->has_mid_face_nodes() ) dst_offset += CN::NumSubEntities( dst->type(), 2 );
    return zero_nodes( dst, 1, dst_offset );
}
ErrorCode moab::HigherOrderFactory::zero_nodes ( ElementSequence dst,
unsigned  nodes_per_elem_to_zero,
unsigned  dst_conn_offset 
) [private]

Definition at line 711 of file HigherOrderFactory.cpp.

References moab::ElementSequence::get_connectivity_array(), MB_SUCCESS, moab::ElementSequence::nodes_per_element(), and moab::EntitySequence::size().

Referenced by zero_mid_edge_nodes(), zero_mid_face_nodes(), and zero_mid_volume_nodes().

{
    unsigned dst_stride    = dst->nodes_per_element();
    EntityHandle* dst_conn = dst->get_connectivity_array();
    if( !dst_conn ) return MB_FAILURE;

    EntityID count = dst->size();
    for( EntityID i = 0; i < count; ++i )
    {
        std::fill( dst_conn + offset, dst_conn + offset + nodes_per_elem, 0 );
        dst_conn += dst_stride;
    }

    return MB_SUCCESS;
}

Member Data Documentation

List of all members.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines