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

#include <WriteSLAC.hpp>

+ Inheritance diagram for moab::WriteSLAC:
+ Collaboration diagram for moab::WriteSLAC:

Classes

struct  DirichletSetData
 struct used to hold data for each nodeset to be output; used by initialize_file to initialize the file header for increased speed More...
struct  MaterialSetData
 struct used to hold data for each block to be output; used by initialize_file to initialize the file header for increased speed More...
class  MeshInfo
 contains the general information about a mesh More...
struct  NeumannSetData
 struct used to hold data for each sideset to be output; used by initialize_file to initialize the file header for increased speed More...

Public Member Functions

 WriteSLAC (Interface *impl)
 Constructor.
virtual ~WriteSLAC ()
 Destructor.
ErrorCode write_file (const char *file_name, const bool overwrite, const FileOptions &opts, const EntityHandle *output_list, const int num_sets, const std::vector< std::string > &qa_list, const Tag *tag_list=NULL, int num_tags=0, int export_dimension=3)
 writes out a file

Static Public Member Functions

static WriterIfacefactory (Interface *)

Protected Member Functions

ErrorCode open_file (const char *filename)
 number of dimensions in this file

Private Member Functions

ErrorCode gather_mesh_information (MeshInfo &mesh_info, std::vector< MaterialSetData > &matset_info, std::vector< NeumannSetData > &neuset_info, std::vector< DirichletSetData > &dirset_info, std::vector< EntityHandle > &matsets, std::vector< EntityHandle > &neusets, std::vector< EntityHandle > &dirsets)
ErrorCode initialize_file (MeshInfo &mesh_info)
ErrorCode write_nodes (const int num_nodes, const Range &nodes, const int dimension)
ErrorCode write_matsets (MeshInfo &mesh_info, std::vector< MaterialSetData > &matset_data, std::vector< NeumannSetData > &neuset_data)
ErrorCode get_valid_sides (Range &elems, const int sense, WriteSLAC::NeumannSetData &sideset_data)
void reset_matset (std::vector< MaterialSetData > &matset_info)
ErrorCode get_neuset_elems (EntityHandle neuset, int current_sense, Range &forward_elems, Range &reverse_elems)
ErrorCode gather_interior_exterior (MeshInfo &mesh_info, std::vector< MaterialSetData > &matset_data, std::vector< NeumannSetData > &neuset_data)

Private Attributes

InterfacembImpl
 interface instance
WriteUtilIfacemWriteIface
std::string fileName
 file name
int ncFile
Tag mMaterialSetTag
 Cached tags for reading. Note that all these tags are defined when the core is initialized.
Tag mDirichletSetTag
Tag mNeumannSetTag
Tag mGlobalIdTag
Tag mMatSetIdTag
Tag mEntityMark

Detailed Description

Definition at line 50 of file WriteSLAC.hpp.


Constructor & Destructor Documentation

Constructor.

get and cache predefined tag handles

Definition at line 75 of file WriteSLAC.cpp.

References DIRICHLET_SET_TAG_NAME, moab::Interface::globalId_tag(), MATERIAL_SET_TAG_NAME, MB_TAG_CREAT, MB_TAG_DENSE, MB_TAG_SPARSE, MB_TYPE_BIT, MB_TYPE_INTEGER, mDirichletSetTag, mEntityMark, mGlobalIdTag, mMaterialSetTag, mMatSetIdTag, mNeumannSetTag, mWriteIface, NEUMANN_SET_TAG_NAME, moab::Interface::query_interface(), and moab::Interface::tag_get_handle().

Referenced by factory().

                                      : mbImpl( impl ), ncFile( 0 )
{
    assert( impl != NULL );

    impl->query_interface( mWriteIface );

    // Initialize in case tag_get_handle fails below
    //! get and cache predefined tag handles
    int negone = -1;
    impl->tag_get_handle( MATERIAL_SET_TAG_NAME, 1, MB_TYPE_INTEGER, mMaterialSetTag, MB_TAG_SPARSE | MB_TAG_CREAT,
                          &negone );

    impl->tag_get_handle( DIRICHLET_SET_TAG_NAME, 1, MB_TYPE_INTEGER, mDirichletSetTag, MB_TAG_SPARSE | MB_TAG_CREAT,
                          &negone );

    impl->tag_get_handle( NEUMANN_SET_TAG_NAME, 1, MB_TYPE_INTEGER, mNeumannSetTag, MB_TAG_SPARSE | MB_TAG_CREAT,
                          &negone );

    mGlobalIdTag = impl->globalId_tag();

    int dum_val = -1;
    impl->tag_get_handle( "__matSetIdTag", 1, MB_TYPE_INTEGER, mMatSetIdTag, MB_TAG_DENSE | MB_TAG_CREAT, &dum_val );

    impl->tag_get_handle( "WriteSLAC element mark", 1, MB_TYPE_BIT, mEntityMark, MB_TAG_CREAT );
}

Member Function Documentation

Definition at line 70 of file WriteSLAC.cpp.

References WriteSLAC().

Referenced by moab::ReaderWriterSet::ReaderWriterSet().

{
    return new WriteSLAC( iface );
}
ErrorCode moab::WriteSLAC::gather_interior_exterior ( MeshInfo mesh_info,
std::vector< MaterialSetData > &  matset_data,
std::vector< NeumannSetData > &  neuset_data 
) [private]

Definition at line 566 of file WriteSLAC.cpp.

References moab::WriteSLAC::MeshInfo::bdy_hexes, moab::WriteSLAC::MeshInfo::bdy_tets, moab::Range::begin(), moab::dum, moab::WriteSLAC::MaterialSetData::elements, moab::WriteSLAC::NeumannSetData::elements, moab::Range::end(), moab::CN::EntityTypeName(), ErrorCode, moab::WriteSLAC::MaterialSetData::id, moab::Range::insert(), MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_INTEGER, MBHEX, mbImpl, MBTET, mMatSetIdTag, moab::WriteSLAC::MaterialSetData::moab_type, moab::WriteSLAC::MeshInfo::num_int_hexes, moab::WriteSLAC::MeshInfo::num_int_tets, moab::Range::size(), moab::Interface::tag_get_handle(), moab::Interface::tag_set_data(), and moab::TYPE_FROM_HANDLE().

Referenced by gather_mesh_information().

{
    // Need to assign a tag with the matset id
    Tag matset_id_tag;
    unsigned int i;
    int dum = -1;
    ErrorCode result =
        mbImpl->tag_get_handle( "__matset_id", 4, MB_TYPE_INTEGER, matset_id_tag, MB_TAG_DENSE | MB_TAG_CREAT, &dum );
    if( MB_SUCCESS != result ) return result;

    Range::iterator rit;
    mesh_info.num_int_hexes = mesh_info.num_int_tets = 0;

    for( i = 0; i < matset_data.size(); i++ )
    {
        WriteSLAC::MaterialSetData matset = matset_data[i];
        if( matset.moab_type == MBHEX )
            mesh_info.num_int_hexes += matset.elements->size();
        else if( matset.moab_type == MBTET )
            mesh_info.num_int_tets += matset.elements->size();
        else
        {
            std::cout << "WriteSLAC doesn't support elements of type " << CN::EntityTypeName( matset.moab_type )
                      << std::endl;
            continue;
        }

        for( rit = matset.elements->begin(); rit != matset.elements->end(); ++rit )
        {
            result = mbImpl->tag_set_data( mMatSetIdTag, &( *rit ), 1, &( matset.id ) );
            if( MB_SUCCESS != result ) return result;
        }
    }

    // Now go through the neumann sets, pulling out the hexes with faces on the
    // boundary
    std::vector< EntityHandle >::iterator vit;
    for( i = 0; i < neuset_data.size(); i++ )
    {
        WriteSLAC::NeumannSetData neuset = neuset_data[i];
        for( vit = neuset.elements.begin(); vit != neuset.elements.end(); ++vit )
        {
            if( TYPE_FROM_HANDLE( *vit ) == MBHEX )
                mesh_info.bdy_hexes.insert( *vit );
            else if( TYPE_FROM_HANDLE( *vit ) == MBTET )
                mesh_info.bdy_tets.insert( *vit );
        }
    }

    // Now we have the number of bdy hexes and tets, we know how many interior ones
    // there are too
    mesh_info.num_int_hexes -= mesh_info.bdy_hexes.size();
    mesh_info.num_int_tets -= mesh_info.bdy_tets.size();

    return MB_SUCCESS;
}
ErrorCode moab::WriteSLAC::gather_mesh_information ( MeshInfo mesh_info,
std::vector< MaterialSetData > &  matset_info,
std::vector< NeumannSetData > &  neuset_info,
std::vector< DirichletSetData > &  dirset_info,
std::vector< EntityHandle > &  matsets,
std::vector< EntityHandle > &  neusets,
std::vector< EntityHandle > &  dirsets 
) [private]

Definition at line 212 of file WriteSLAC.cpp.

References moab::Range::begin(), moab::CN::Dimension(), moab::WriteSLAC::MaterialSetData::element_type, moab::WriteSLAC::MaterialSetData::elements, moab::WriteSLAC::NeumannSetData::elements, moab::Range::end(), ErrorCode, moab::EXOII_MAX_ELEM_TYPE, gather_interior_exterior(), moab::WriteUtilIface::gather_nodes_from_elements(), moab::Interface::get_connectivity(), moab::ExoIIUtil::get_element_type_from_num_verts(), moab::Interface::get_entities_by_handle(), get_neuset_elems(), moab::Interface::get_parent_meshsets(), get_valid_sides(), moab::WriteSLAC::MaterialSetData::id, moab::WriteSLAC::DirichletSetData::id, moab::WriteSLAC::NeumannSetData::id, MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TYPE_BIT, MBEDGE, mbImpl, MBMAXTYPE, MBQUAD, MBTRI, MBVERTEX, mDirichletSetTag, mEntityMark, moab::WriteSLAC::NeumannSetData::mesh_set_handle, mMaterialSetTag, mNeumannSetTag, moab::WriteSLAC::MaterialSetData::moab_type, mWriteIface, moab::WriteSLAC::DirichletSetData::nodes, moab::WriteSLAC::MeshInfo::nodes, moab::WriteSLAC::MeshInfo::num_dim, moab::WriteSLAC::MeshInfo::num_elements, moab::WriteSLAC::MeshInfo::num_matsets, moab::WriteSLAC::MeshInfo::num_nodes, moab::WriteSLAC::MaterialSetData::number_attributes, moab::WriteSLAC::MaterialSetData::number_elements, moab::WriteSLAC::NeumannSetData::number_elements, moab::WriteSLAC::DirichletSetData::number_nodes, moab::WriteSLAC::MaterialSetData::number_nodes_per_element, moab::Range::size(), moab::Interface::tag_delete(), moab::Interface::tag_get_data(), moab::Interface::tag_get_handle(), moab::Interface::tag_set_data(), moab::TYPE_FROM_HANDLE(), moab::Interface::type_from_handle(), and moab::ExoIIUtil::VerticesPerElement.

Referenced by write_file().

{
    std::vector< EntityHandle >::iterator vector_iter, end_vector_iter;

    mesh_info.num_nodes    = 0;
    mesh_info.num_elements = 0;
    mesh_info.num_matsets  = 0;

    int id = 0;

    vector_iter     = matsets.begin();
    end_vector_iter = matsets.end();

    mesh_info.num_matsets = matsets.size();

    std::vector< EntityHandle > parent_meshsets;

    // Clean out the bits for the element mark
    mbImpl->tag_delete( mEntityMark );
    mbImpl->tag_get_handle( "WriteSLAC element mark", 1, MB_TYPE_BIT, mEntityMark, MB_TAG_CREAT );

    int highest_dimension_of_element_matsets = 0;

    for( vector_iter = matsets.begin(); vector_iter != matsets.end(); ++vector_iter )
    {
        WriteSLAC::MaterialSetData matset_data;
        matset_data.elements = new Range;

        // For the purpose of qa records, get the parents of these matsets
        if( mbImpl->get_parent_meshsets( *vector_iter, parent_meshsets ) != MB_SUCCESS ) return MB_FAILURE;

        // Get all Entity Handles in the mesh set
        Range dummy_range;
        mbImpl->get_entities_by_handle( *vector_iter, dummy_range, true );

        // Wait a minute, we are doing some filtering here that doesn't make sense at this level CJS

        // Find the dimension of the last entity in this range
        Range::iterator entity_iter = dummy_range.end();
        entity_iter                 = dummy_range.end();
        --entity_iter;
        int this_dim = CN::Dimension( TYPE_FROM_HANDLE( *entity_iter ) );
        entity_iter  = dummy_range.begin();
        while( entity_iter != dummy_range.end() && CN::Dimension( TYPE_FROM_HANDLE( *entity_iter ) ) != this_dim )
            ++entity_iter;

        if( entity_iter != dummy_range.end() )
            std::copy( entity_iter, dummy_range.end(), range_inserter( *( matset_data.elements ) ) );

        assert( matset_data.elements->begin() == matset_data.elements->end() ||
                CN::Dimension( TYPE_FROM_HANDLE( *( matset_data.elements->begin() ) ) ) == this_dim );

        // Get the matset's id
        if( mbImpl->tag_get_data( mMaterialSetTag, &( *vector_iter ), 1, &id ) != MB_SUCCESS )
        {
            MB_SET_ERR( MB_FAILURE, "Couldn't get matset id from a tag for an element matset" );
        }

        matset_data.id                = id;
        matset_data.number_attributes = 0;

        // Iterate through all the elements in the meshset
        Range::iterator elem_range_iter, end_elem_range_iter;
        elem_range_iter     = matset_data.elements->begin();
        end_elem_range_iter = matset_data.elements->end();

        // Get the entity type for this matset, verifying that it's the same for all elements
        // THIS ASSUMES HANDLES SORT BY TYPE!!!
        EntityType entity_type = TYPE_FROM_HANDLE( *elem_range_iter );
        --end_elem_range_iter;
        if( entity_type != TYPE_FROM_HANDLE( *( end_elem_range_iter++ ) ) )
        {
            MB_SET_ERR( MB_FAILURE, "Entities in matset " << id << " not of common type" );
        }

        int dimension = -1;
        if( entity_type == MBQUAD || entity_type == MBTRI )
            dimension = 3;  // Output shells by default
        else if( entity_type == MBEDGE )
            dimension = 2;
        else
            dimension = CN::Dimension( entity_type );

        if( dimension > highest_dimension_of_element_matsets ) highest_dimension_of_element_matsets = dimension;

        matset_data.moab_type = mbImpl->type_from_handle( *( matset_data.elements->begin() ) );
        if( MBMAXTYPE == matset_data.moab_type ) return MB_FAILURE;

        std::vector< EntityHandle > tmp_conn;
        mbImpl->get_connectivity( &( *( matset_data.elements->begin() ) ), 1, tmp_conn );
        matset_data.element_type =
            ExoIIUtil::get_element_type_from_num_verts( tmp_conn.size(), entity_type, dimension );

        if( matset_data.element_type == EXOII_MAX_ELEM_TYPE )
        {
            MB_SET_ERR( MB_FAILURE, "Element type in matset " << id << " didn't get set correctly" );
        }

        matset_data.number_nodes_per_element = ExoIIUtil::VerticesPerElement[matset_data.element_type];

        // Number of nodes for this matset
        matset_data.number_elements = matset_data.elements->size();

        // Total number of elements
        mesh_info.num_elements += matset_data.number_elements;

        // Get the nodes for the elements
        mWriteIface->gather_nodes_from_elements( *matset_data.elements, mEntityMark, mesh_info.nodes );

        if( !neusets.empty() )
        {
            // If there are neusets, keep track of which elements are being written out
            for( Range::iterator iter = matset_data.elements->begin(); iter != matset_data.elements->end(); ++iter )
            {
                unsigned char bit = 0x1;
                mbImpl->tag_set_data( mEntityMark, &( *iter ), 1, &bit );
            }
        }

        matset_info.push_back( matset_data );
    }

    // If user hasn't entered dimension, we figure it out
    if( mesh_info.num_dim == 0 )
    {
        // Never want 1 or zero dimensions
        if( highest_dimension_of_element_matsets < 2 )
            mesh_info.num_dim = 3;
        else
            mesh_info.num_dim = highest_dimension_of_element_matsets;
    }

    Range::iterator range_iter, end_range_iter;
    range_iter     = mesh_info.nodes.begin();
    end_range_iter = mesh_info.nodes.end();

    mesh_info.num_nodes = mesh_info.nodes.size();

    //------dirsets--------

    vector_iter     = dirsets.begin();
    end_vector_iter = dirsets.end();

    for( ; vector_iter != end_vector_iter; ++vector_iter )
    {
        WriteSLAC::DirichletSetData dirset_data;
        dirset_data.id           = 0;
        dirset_data.number_nodes = 0;

        // Get the dirset's id
        if( mbImpl->tag_get_data( mDirichletSetTag, &( *vector_iter ), 1, &id ) != MB_SUCCESS )
        {
            MB_SET_ERR( MB_FAILURE, "Couldn't get id tag for dirset " << id );
        }

        dirset_data.id = id;

        std::vector< EntityHandle > node_vector;
        // Get the nodes of the dirset that are in mesh_info.nodes
        if( mbImpl->get_entities_by_handle( *vector_iter, node_vector, true ) != MB_SUCCESS )
        {
            MB_SET_ERR( MB_FAILURE, "Couldn't get nodes in dirset " << id );
        }

        std::vector< EntityHandle >::iterator iter, end_iter;
        iter     = node_vector.begin();
        end_iter = node_vector.end();

        int j                     = 0;
        unsigned char node_marked = 0;
        ErrorCode result;
        for( ; iter != end_iter; ++iter )
        {
            if( TYPE_FROM_HANDLE( *iter ) != MBVERTEX ) continue;
            result = mbImpl->tag_get_data( mEntityMark, &( *iter ), 1, &node_marked );MB_CHK_SET_ERR( result, "Couldn't get mark data" );

            if( 0x1 == node_marked ) dirset_data.nodes.push_back( *iter );
            j++;
        }

        dirset_data.number_nodes = dirset_data.nodes.size();
        dirset_info.push_back( dirset_data );
    }

    //------neusets--------
    vector_iter     = neusets.begin();
    end_vector_iter = neusets.end();

    for( ; vector_iter != end_vector_iter; ++vector_iter )
    {
        WriteSLAC::NeumannSetData neuset_data;

        // Get the neuset's id
        if( mbImpl->tag_get_data( mNeumannSetTag, &( *vector_iter ), 1, &id ) != MB_SUCCESS ) return MB_FAILURE;

        neuset_data.id              = id;
        neuset_data.mesh_set_handle = *vector_iter;

        // Get the sides in two lists, one forward the other reverse; starts with forward sense
        // by convention
        Range forward_elems, reverse_elems;
        if( get_neuset_elems( *vector_iter, 0, forward_elems, reverse_elems ) == MB_FAILURE ) return MB_FAILURE;

        ErrorCode result = get_valid_sides( forward_elems, 1, neuset_data );MB_CHK_SET_ERR( result, "Couldn't get valid sides data" );
        result = get_valid_sides( reverse_elems, -1, neuset_data );MB_CHK_SET_ERR( result, "Couldn't get valid sides data" );

        neuset_data.number_elements = neuset_data.elements.size();
        neuset_info.push_back( neuset_data );
    }

    // Get information about interior/exterior tets/hexes, and mark matset ids
    return gather_interior_exterior( mesh_info, matset_info, neuset_info );
}
ErrorCode moab::WriteSLAC::get_neuset_elems ( EntityHandle  neuset,
int  current_sense,
Range forward_elems,
Range reverse_elems 
) [private]

Definition at line 958 of file WriteSLAC.cpp.

References moab::Range::begin(), moab::CN::Dimension(), moab::Range::end(), moab::Range::erase(), ErrorCode, moab::Interface::get_entities_by_handle(), MB_TYPE_INTEGER, MBENTITYSET, mbImpl, moab::Interface::tag_get_data(), moab::Interface::tag_get_handle(), and moab::TYPE_FROM_HANDLE().

Referenced by gather_mesh_information().

{
    Range ss_elems, ss_meshsets;

    // Get the sense tag; don't need to check return, might be an error if the tag
    // hasn't been created yet
    Tag sense_tag = 0;
    mbImpl->tag_get_handle( "SENSE", 1, MB_TYPE_INTEGER, sense_tag );

    // Get the entities in this set
    ErrorCode result = mbImpl->get_entities_by_handle( neuset, ss_elems, true );
    if( MB_FAILURE == result ) return result;

    // Now remove the meshsets into the ss_meshsets; first find the first meshset,
    Range::iterator range_iter = ss_elems.begin();
    while( TYPE_FROM_HANDLE( *range_iter ) != MBENTITYSET && range_iter != ss_elems.end() )
        ++range_iter;

    // Then, if there are some, copy them into ss_meshsets and erase from ss_elems
    if( range_iter != ss_elems.end() )
    {
        std::copy( range_iter, ss_elems.end(), range_inserter( ss_meshsets ) );
        ss_elems.erase( range_iter, ss_elems.end() );
    }

    // OK, for the elements, check the sense of this set and copy into the right range
    // (if the sense is 0, copy into both ranges)

    // Need to step forward on list until we reach the right dimension
    Range::iterator dum_it = ss_elems.end();
    --dum_it;
    int target_dim = CN::Dimension( TYPE_FROM_HANDLE( *dum_it ) );
    dum_it         = ss_elems.begin();
    while( target_dim != CN::Dimension( TYPE_FROM_HANDLE( *dum_it ) ) && dum_it != ss_elems.end() )
        ++dum_it;

    if( current_sense == 1 || current_sense == 0 ) std::copy( dum_it, ss_elems.end(), range_inserter( forward_elems ) );
    if( current_sense == -1 || current_sense == 0 )
        std::copy( dum_it, ss_elems.end(), range_inserter( reverse_elems ) );

    // Now loop over the contained meshsets, getting the sense of those and calling this
    // function recursively
    for( range_iter = ss_meshsets.begin(); range_iter != ss_meshsets.end(); ++range_iter )
    {
        // First get the sense; if it's not there, by convention it's forward
        int this_sense;
        if( 0 == sense_tag || MB_FAILURE == mbImpl->tag_get_data( sense_tag, &( *range_iter ), 1, &this_sense ) )
            this_sense = 1;

        // Now get all the entities on this meshset, with the proper (possibly reversed) sense
        get_neuset_elems( *range_iter, this_sense * current_sense, forward_elems, reverse_elems );
    }

    return result;
}
ErrorCode moab::WriteSLAC::get_valid_sides ( Range elems,
const int  sense,
WriteSLAC::NeumannSetData sideset_data 
) [private]

Definition at line 432 of file WriteSLAC.cpp.

References moab::Range::begin(), moab::CN::Dimension(), moab::WriteSLAC::NeumannSetData::elements, moab::Range::end(), ErrorCode, moab::Interface::get_adjacencies(), moab::WriteSLAC::NeumannSetData::id, MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, mbImpl, mEntityMark, moab::Interface::side_number(), moab::WriteSLAC::NeumannSetData::side_numbers, moab::Interface::tag_get_data(), and moab::TYPE_FROM_HANDLE().

Referenced by gather_mesh_information().

{
    // This is where we see if underlying element of side set element is included in output

    unsigned char element_marked = 0;
    ErrorCode result;
    for( Range::iterator iter = elems.begin(); iter != elems.end(); ++iter )
    {
        // Should insert here if "side" is a quad/tri on a quad/tri mesh
        result = mbImpl->tag_get_data( mEntityMark, &( *iter ), 1, &element_marked );MB_CHK_SET_ERR( result, "Couldn't get mark data" );

        if( 0x1 == element_marked )
        {
            neuset_data.elements.push_back( *iter );

            // TJT TODO: the sense should really be # edges + 1or2
            neuset_data.side_numbers.push_back( ( sense == 1 ? 1 : 2 ) );
        }
        else
        {  // Then "side" is probably a quad/tri on a hex/tet mesh
            std::vector< EntityHandle > parents;
            int dimension = CN::Dimension( TYPE_FROM_HANDLE( *iter ) );

            // Get the adjacent parent element of "side"
            if( mbImpl->get_adjacencies( &( *iter ), 1, dimension + 1, false, parents ) != MB_SUCCESS )
            {
                MB_SET_ERR( MB_FAILURE, "Couldn't get adjacencies for neuset" );
            }

            if( !parents.empty() )
            {
                // Make sure the adjacent parent element will be output
                for( unsigned int k = 0; k < parents.size(); k++ )
                {
                    result = mbImpl->tag_get_data( mEntityMark, &( parents[k] ), 1, &element_marked );MB_CHK_SET_ERR( result, "Couldn't get mark data" );

                    int side_no, this_sense, this_offset;
                    if( 0x1 == element_marked &&
                        mbImpl->side_number( parents[k], *iter, side_no, this_sense, this_offset ) == MB_SUCCESS &&
                        this_sense == sense )
                    {
                        neuset_data.elements.push_back( parents[k] );
                        neuset_data.side_numbers.push_back( side_no + 1 );
                        break;
                    }
                }
            }
            else
            {
                MB_SET_ERR( MB_FAILURE, "No parent element exists for element in neuset " << neuset_data.id );
            }
        }
    }

    return MB_SUCCESS;
}

Definition at line 829 of file WriteSLAC.cpp.

References moab::WriteSLAC::MeshInfo::bdy_hexes, moab::WriteSLAC::MeshInfo::bdy_tets, MB_SET_ERR, MB_SUCCESS, ncFile, moab::WriteSLAC::MeshInfo::num_dim, moab::WriteSLAC::MeshInfo::num_int_hexes, moab::WriteSLAC::MeshInfo::num_int_tets, moab::WriteSLAC::MeshInfo::num_nodes, and moab::Range::size().

Referenced by write_file().

{
    // Perform the initializations

    int coord_size = -1, ncoords = -1;
    // Initialization to avoid warnings on Linux
    int hexinterior = -1, hexinteriorsize, hexexterior = -1, hexexteriorsize = -1;
    int tetinterior = -1, tetinteriorsize, tetexterior = -1, tetexteriorsize = -1;

    if( nc_def_dim( ncFile, "coord_size", (size_t)mesh_info.num_dim, &coord_size ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of dimensions" );
    }

    if( nc_def_dim( ncFile, "ncoords", (size_t)mesh_info.num_nodes, &ncoords ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of nodes" );
    }

    if( 0 != mesh_info.num_int_hexes &&
        nc_def_dim( ncFile, "hexinterior", (size_t)mesh_info.num_int_hexes, &hexinterior ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of interior hex elements" );
    }

    if( nc_def_dim( ncFile, "hexinteriorsize", (size_t)9, &hexinteriorsize ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define interior hex element size" );
    }

    if( 0 != mesh_info.bdy_hexes.size() &&
        nc_def_dim( ncFile, "hexexterior", (size_t)mesh_info.bdy_hexes.size(), &hexexterior ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of exterior hex elements" );
    }

    if( nc_def_dim( ncFile, "hexexteriorsize", (size_t)15, &hexexteriorsize ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define exterior hex element size" );
    }

    if( 0 != mesh_info.num_int_tets &&
        nc_def_dim( ncFile, "tetinterior", (size_t)mesh_info.num_int_tets, &tetinterior ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of interior tet elements" );
    }

    if( nc_def_dim( ncFile, "tetinteriorsize", (size_t)5, &tetinteriorsize ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define interior tet element size" );
    }

    if( 0 != mesh_info.bdy_tets.size() &&
        nc_def_dim( ncFile, "tetexterior", (size_t)mesh_info.bdy_tets.size(), &tetexterior ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of exterior tet elements" );
    }

    if( nc_def_dim( ncFile, "tetexteriorsize", (size_t)9, &tetexteriorsize ) != NC_NOERR )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define exterior tet element size" );
    }

    /* ...and some variables */

    int dims[2];
    dims[0] = hexinterior;
    dims[1] = hexinteriorsize;
    int dum_var;
    if( 0 != mesh_info.num_int_hexes &&
        NC_NOERR != nc_def_var( ncFile, "hexahedron_interior", NC_LONG, 2, dims, &dum_var ) )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to create connectivity array for interior hexes" );
    }

    dims[0] = hexexterior;
    dims[1] = hexexteriorsize;
    if( 0 != mesh_info.bdy_hexes.size() &&
        NC_NOERR != nc_def_var( ncFile, "hexahedron_exterior", NC_LONG, 2, dims, &dum_var ) )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to create connectivity array for exterior hexes" );
    }

    dims[0] = tetinterior;
    dims[1] = tetinteriorsize;
    if( 0 != mesh_info.num_int_tets &&
        NC_NOERR != nc_def_var( ncFile, "tetrahedron_exterior", NC_LONG, 2, dims, &dum_var ) )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to create connectivity array for interior tets" );
    }

    dims[0] = tetexterior;
    dims[1] = tetexteriorsize;
    if( 0 != mesh_info.bdy_tets.size() &&
        NC_NOERR != nc_def_var( ncFile, "tetrahedron_exterior", NC_LONG, 2, dims, &dum_var ) )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to create connectivity array for exterior tets" );
    }

    /* Node coordinate arrays: */

    dims[0] = ncoords;
    dims[1] = coord_size;
    if( NC_NOERR != nc_def_var( ncFile, "coords", NC_DOUBLE, 2, dims, &dum_var ) )
    {
        MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define node coordinate array" );
    }

    return MB_SUCCESS;
}
ErrorCode moab::WriteSLAC::open_file ( const char *  filename) [protected]

number of dimensions in this file

open a file for writing

Definition at line 940 of file WriteSLAC.cpp.

References moab::fail(), MB_SET_ERR, MB_SUCCESS, and ncFile.

{
    // Not a valid filname
    if( strlen( (const char*)filename ) == 0 )
    {
        MB_SET_ERR( MB_FAILURE, "Output filename not specified" );
    }

    int fail = nc_create( filename, NC_CLOBBER, &ncFile );
    // File couldn't be opened
    if( NC_NOERR != fail )
    {
        MB_SET_ERR( MB_FAILURE, "Cannot open " << filename );
    }

    return MB_SUCCESS;
}
void moab::WriteSLAC::reset_matset ( std::vector< MaterialSetData > &  matset_info) [private]

Definition at line 107 of file WriteSLAC.cpp.

Referenced by write_file().

{
    std::vector< WriteSLAC::MaterialSetData >::iterator iter;

    for( iter = matset_info.begin(); iter != matset_info.end(); ++iter )
        delete( *iter ).elements;
}
ErrorCode moab::WriteSLAC::write_file ( const char *  file_name,
const bool  overwrite,
const FileOptions opts,
const EntityHandle output_list,
const int  num_sets,
const std::vector< std::string > &  qa_list,
const Tag tag_list = NULL,
int  num_tags = 0,
int  export_dimension = 3 
) [virtual]

writes out a file

Implements moab::WriterIface.

Definition at line 115 of file WriteSLAC.cpp.

References moab::Range::begin(), moab::Range::clear(), moab::Range::end(), entities, moab::fail(), fileName, gather_mesh_information(), moab::Interface::get_entities_by_type_and_tag(), initialize_file(), MB_FILE_WRITE_ERROR, MB_SUCCESS, MBENTITYSET, mbImpl, mDirichletSetTag, mMaterialSetTag, mNeumannSetTag, ncFile, moab::WriteSLAC::MeshInfo::nodes, moab::WriteSLAC::MeshInfo::num_dim, moab::WriteSLAC::MeshInfo::num_nodes, reset_matset(), moab::Interface::tag_get_data(), write_matsets(), and write_nodes().

{
    assert( 0 != mMaterialSetTag && 0 != mNeumannSetTag && 0 != mDirichletSetTag );

    // Check the file name
    if( NULL == strstr( file_name, ".ncdf" ) ) return MB_FAILURE;

    std::vector< EntityHandle > matsets, dirsets, neusets, entities;

    fileName = file_name;

    // Separate into material sets, dirichlet sets, neumann sets

    if( num_sets == 0 )
    {
        // Default to all defined sets
        Range this_range;
        mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mMaterialSetTag, NULL, 1, this_range );
        std::copy( this_range.begin(), this_range.end(), std::back_inserter( matsets ) );
        this_range.clear();
        mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mDirichletSetTag, NULL, 1, this_range );
        std::copy( this_range.begin(), this_range.end(), std::back_inserter( dirsets ) );
        this_range.clear();
        mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mNeumannSetTag, NULL, 1, this_range );
        std::copy( this_range.begin(), this_range.end(), std::back_inserter( neusets ) );
    }
    else
    {
        int dummy;
        for( const EntityHandle* iter = ent_handles; iter < ent_handles + num_sets; ++iter )
        {
            if( MB_SUCCESS == mbImpl->tag_get_data( mMaterialSetTag, &( *iter ), 1, &dummy ) )
                matsets.push_back( *iter );
            else if( MB_SUCCESS == mbImpl->tag_get_data( mDirichletSetTag, &( *iter ), 1, &dummy ) )
                dirsets.push_back( *iter );
            else if( MB_SUCCESS == mbImpl->tag_get_data( mNeumannSetTag, &( *iter ), 1, &dummy ) )
                neusets.push_back( *iter );
        }
    }

    // If there is nothing to write just return.
    if( matsets.empty() && dirsets.empty() && neusets.empty() ) return MB_FILE_WRITE_ERROR;

    std::vector< WriteSLAC::MaterialSetData > matset_info;
    std::vector< WriteSLAC::DirichletSetData > dirset_info;
    std::vector< WriteSLAC::NeumannSetData > neuset_info;

    MeshInfo mesh_info;

    matset_info.clear();
    if( gather_mesh_information( mesh_info, matset_info, neuset_info, dirset_info, matsets, neusets, dirsets ) !=
        MB_SUCCESS )
    {
        reset_matset( matset_info );
        return MB_FAILURE;
    }

    // Try to open the file after gather mesh info succeeds
    int fail = nc_create( file_name, overwrite ? NC_CLOBBER : NC_NOCLOBBER, &ncFile );
    if( NC_NOERR != fail )
    {
        reset_matset( matset_info );
        return MB_FAILURE;
    }

    if( initialize_file( mesh_info ) != MB_SUCCESS )
    {
        reset_matset( matset_info );
        return MB_FAILURE;
    }

    if( write_nodes( mesh_info.num_nodes, mesh_info.nodes, mesh_info.num_dim ) != MB_SUCCESS )
    {
        reset_matset( matset_info );
        return MB_FAILURE;
    }

    if( write_matsets( mesh_info, matset_info, neuset_info ) )
    {
        reset_matset( matset_info );
        return MB_FAILURE;
    }

    fail = nc_close( ncFile );
    if( NC_NOERR != fail ) return MB_FAILURE;

    return MB_SUCCESS;
}
ErrorCode moab::WriteSLAC::write_matsets ( MeshInfo mesh_info,
std::vector< MaterialSetData > &  matset_data,
std::vector< NeumannSetData > &  neuset_data 
) [private]

Definition at line 625 of file WriteSLAC.cpp.

References moab::WriteSLAC::MeshInfo::bdy_hexes, moab::WriteSLAC::MeshInfo::bdy_tets, moab::Range::begin(), moab::WriteSLAC::MaterialSetData::elements, moab::Range::end(), ErrorCode, moab::fail(), moab::Range::find(), moab::Interface::get_connectivity(), GET_VAR, moab::WriteSLAC::MaterialSetData::id, MB_SUCCESS, MBHEX, mbImpl, MBTET, mGlobalIdTag, mMatSetIdTag, moab::WriteSLAC::MaterialSetData::moab_type, ncFile, moab::WriteSLAC::MeshInfo::num_int_hexes, moab::WriteSLAC::MeshInfo::num_int_tets, moab::Range::size(), and moab::Interface::tag_get_data().

Referenced by write_file().

{
    unsigned int i;
    std::vector< int > connect;
    const EntityHandle* connecth;
    int num_connecth;
    ErrorCode result;

    // First write the interior hexes
    int hex_conn = -1;
    std::vector< int > dims;
    if( mesh_info.bdy_hexes.size() != 0 || mesh_info.num_int_hexes != 0 )
    {
        GET_VAR( "hexahedron_interior", hex_conn, dims );
        if( -1 == hex_conn ) return MB_FAILURE;
    }
    connect.reserve( 13 );
    Range::iterator rit;

    int elem_num = 0;
    WriteSLAC::MaterialSetData matset;
    size_t start[2] = { 0, 0 }, count[2] = { 1, 1 };
    int fail;
    for( i = 0; i < matset_data.size(); i++ )
    {
        matset = matset_data[i];
        if( matset.moab_type != MBHEX ) continue;

        int id     = matset.id;
        connect[0] = id;

        for( rit = matset.elements->begin(); rit != matset.elements->end(); ++rit )
        {
            // Skip if it's on the bdy
            if( mesh_info.bdy_hexes.find( *rit ) != mesh_info.bdy_hexes.end() ) continue;

            // Get the connectivity of this element
            result = mbImpl->get_connectivity( *rit, connecth, num_connecth );
            if( MB_SUCCESS != result ) return result;

            // Get the vertex ids
            result = mbImpl->tag_get_data( mGlobalIdTag, connecth, num_connecth, &connect[1] );
            if( MB_SUCCESS != result ) return result;

            // Put the variable at the right position
            start[0] = elem_num++;
            count[1] = 9;

            // Write the data
            fail = nc_put_vara_int( ncFile, hex_conn, start, count, &connect[0] );
            if( NC_NOERR != fail ) return MB_FAILURE;
        }
    }

    int tet_conn = -1;
    if( mesh_info.bdy_tets.size() != 0 || mesh_info.num_int_tets != 0 )
    {
        GET_VAR( "tetrahedron_interior", tet_conn, dims );
        if( -1 == tet_conn ) return MB_FAILURE;
    }

    // Now the interior tets
    elem_num = 0;
    for( i = 0; i < matset_data.size(); i++ )
    {
        matset = matset_data[i];
        if( matset.moab_type != MBTET ) continue;

        int id     = matset.id;
        connect[0] = id;
        elem_num   = 0;
        for( rit = matset.elements->begin(); rit != matset.elements->end(); ++rit )
        {
            // Skip if it's on the bdy
            if( mesh_info.bdy_tets.find( *rit ) != mesh_info.bdy_tets.end() ) continue;

            // Get the connectivity of this element
            result = mbImpl->get_connectivity( *rit, connecth, num_connecth );
            if( MB_SUCCESS != result ) return result;

            // Get the vertex ids
            result = mbImpl->tag_get_data( mGlobalIdTag, connecth, num_connecth, &connect[1] );
            if( MB_SUCCESS != result ) return result;

            // Put the variable at the right position
            start[0] = elem_num++;
            count[1] = 5;
            fail     = nc_put_vara_int( ncFile, tet_conn, start, count, &connect[0] );
            // Write the data
            if( NC_NOERR != fail ) return MB_FAILURE;
        }
    }

    // Now the exterior hexes
    if( mesh_info.bdy_hexes.size() != 0 )
    {
        hex_conn = -1;
        GET_VAR( "hexahedron_exterior", hex_conn, dims );
        if( -1 == hex_conn ) return MB_FAILURE;

        connect.reserve( 15 );
        elem_num = 0;

        // Write the elements
        for( rit = mesh_info.bdy_hexes.begin(); rit != mesh_info.bdy_hexes.end(); ++rit )
        {
            // Get the material set for this hex
            result = mbImpl->tag_get_data( mMatSetIdTag, &( *rit ), 1, &connect[0] );
            if( MB_SUCCESS != result ) return result;

            // Get the connectivity of this element
            result = mbImpl->get_connectivity( *rit, connecth, num_connecth );
            if( MB_SUCCESS != result ) return result;

            // Get the vertex ids
            result = mbImpl->tag_get_data( mGlobalIdTag, connecth, num_connecth, &connect[1] );
            if( MB_SUCCESS != result ) return result;

            // Preset side numbers
            for( i = 9; i < 15; i++ )
                connect[i] = -1;

            // Now write the side numbers
            for( i = 0; i < neuset_data.size(); i++ )
            {
                std::vector< EntityHandle >::iterator vit =
                    std::find( neuset_data[i].elements.begin(), neuset_data[i].elements.end(), *rit );
                while( vit != neuset_data[i].elements.end() )
                {
                    // Have a side - get the side # and put in connect array
                    int side_no          = neuset_data[i].side_numbers[vit - neuset_data[i].elements.begin()];
                    connect[9 + side_no] = neuset_data[i].id;
                    ++vit;
                    vit = std::find( vit, neuset_data[i].elements.end(), *rit );
                }
            }

            // Put the variable at the right position
            start[0] = elem_num++;
            count[1] = 15;
            fail     = nc_put_vara_int( ncFile, hex_conn, start, count, &connect[0] );
            // Write the data
            if( NC_NOERR != fail ) return MB_FAILURE;
        }
    }

    // Now the exterior tets
    if( mesh_info.bdy_tets.size() != 0 )
    {
        tet_conn = -1;
        GET_VAR( "tetrahedron_exterior", tet_conn, dims );
        if( -1 == tet_conn ) return MB_FAILURE;

        connect.reserve( 9 );
        elem_num = 0;

        // Write the elements
        for( rit = mesh_info.bdy_tets.begin(); rit != mesh_info.bdy_tets.end(); ++rit )
        {
            // Get the material set for this tet
            result = mbImpl->tag_get_data( mMatSetIdTag, &( *rit ), 1, &connect[0] );
            if( MB_SUCCESS != result ) return result;

            // Get the connectivity of this element
            result = mbImpl->get_connectivity( *rit, connecth, num_connecth );
            if( MB_SUCCESS != result ) return result;

            // Get the vertex ids
            result = mbImpl->tag_get_data( mGlobalIdTag, connecth, num_connecth, &connect[1] );
            if( MB_SUCCESS != result ) return result;

            // Preset side numbers
            for( i = 5; i < 9; i++ )
                connect[i] = -1;

            // Now write the side numbers
            for( i = 0; i < neuset_data.size(); i++ )
            {
                std::vector< EntityHandle >::iterator vit =
                    std::find( neuset_data[i].elements.begin(), neuset_data[i].elements.end(), *rit );
                while( vit != neuset_data[i].elements.end() )
                {
                    // Have a side - get the side # and put in connect array
                    int side_no          = neuset_data[i].side_numbers[vit - neuset_data[i].elements.begin()];
                    connect[5 + side_no] = neuset_data[i].id;
                    ++vit;
                    vit = std::find( vit, neuset_data[i].elements.end(), *rit );
                }
            }

            // Put the variable at the right position
            start[0] = elem_num++;
            count[1] = 9;
            fail     = nc_put_vara_int( ncFile, tet_conn, start, count, &connect[0] );
            // Write the data
            if( NC_NOERR != fail ) return MB_FAILURE;
        }
    }

    return MB_SUCCESS;
}
ErrorCode moab::WriteSLAC::write_nodes ( const int  num_nodes,
const Range nodes,
const int  dimension 
) [private]

Definition at line 489 of file WriteSLAC.cpp.

References ErrorCode, moab::fail(), moab::WriteUtilIface::get_node_coords(), GET_VAR, MB_CHK_SET_ERR, MB_SUCCESS, MB_TAG_NOT_FOUND, MB_TYPE_DOUBLE, mbImpl, mesh, MESH_TRANSFORM_TAG_NAME, mGlobalIdTag, mWriteIface, ncFile, moab::Interface::tag_get_data(), and moab::Interface::tag_get_handle().

Referenced by write_file().

{
    // See if should transform coordinates
    ErrorCode result;
    Tag trans_tag;
    result                = mbImpl->tag_get_handle( MESH_TRANSFORM_TAG_NAME, 16, MB_TYPE_DOUBLE, trans_tag );
    bool transform_needed = true;
    if( result == MB_TAG_NOT_FOUND ) transform_needed = false;

    int num_coords_to_fill = transform_needed ? 3 : dimension;

    std::vector< double* > coord_arrays( 3 );
    coord_arrays[0] = new double[num_nodes];
    coord_arrays[1] = new double[num_nodes];
    coord_arrays[2] = NULL;

    if( num_coords_to_fill == 3 ) coord_arrays[2] = new double[num_nodes];

    result = mWriteIface->get_node_coords( dimension, num_nodes, nodes, mGlobalIdTag, 0, coord_arrays );
    if( result != MB_SUCCESS )
    {
        delete[] coord_arrays[0];
        delete[] coord_arrays[1];
        if( coord_arrays[2] ) delete[] coord_arrays[2];
        return result;
    }

    if( transform_needed )
    {
        double trans_matrix[16];
        const EntityHandle mesh = 0;
        result                  = mbImpl->tag_get_data( trans_tag, &mesh, 1, trans_matrix );MB_CHK_SET_ERR( result, "Couldn't get transform data" );

        for( int i = 0; i < num_nodes; i++ )
        {
            double vec1[3];
            double vec2[3];

            vec2[0] = coord_arrays[0][i];
            vec2[1] = coord_arrays[1][i];
            vec2[2] = coord_arrays[2][i];

            for( int row = 0; row < 3; row++ )
            {
                vec1[row] = 0.0;
                for( int col = 0; col < 3; col++ )
                    vec1[row] += ( trans_matrix[( row * 4 ) + col] * vec2[col] );
            }

            coord_arrays[0][i] = vec1[0];
            coord_arrays[1][i] = vec1[1];
            coord_arrays[2][i] = vec1[2];
        }
    }

    // Write the nodes
    int nc_var = -1;
    std::vector< int > dims;
    GET_VAR( "coords", nc_var, dims );
    if( -1 == nc_var ) return MB_FAILURE;
    size_t start[2] = { 0, 0 }, count[2] = { static_cast< size_t >( num_nodes ), 1 };
    int fail = nc_put_vara_double( ncFile, nc_var, start, count, coord_arrays[0] );
    if( NC_NOERR != fail ) return MB_FAILURE;
    start[1] = 1;
    fail     = nc_put_vara_double( ncFile, nc_var, start, count, coord_arrays[1] );
    if( NC_NOERR != fail ) return MB_FAILURE;
    start[1] = 2;
    fail     = nc_put_vara_double( ncFile, nc_var, start, count, coord_arrays[2] );
    if( NC_NOERR != fail ) return MB_FAILURE;

    delete[] coord_arrays[0];
    delete[] coord_arrays[1];
    if( coord_arrays[2] ) delete[] coord_arrays[2];

    return MB_SUCCESS;
}

Member Data Documentation

std::string moab::WriteSLAC::fileName [private]

file name

Definition at line 139 of file WriteSLAC.hpp.

Referenced by write_file().

Definition at line 145 of file WriteSLAC.hpp.

Referenced by gather_mesh_information(), write_file(), and WriteSLAC().

Definition at line 147 of file WriteSLAC.hpp.

Referenced by write_matsets(), write_nodes(), and WriteSLAC().

Cached tags for reading. Note that all these tags are defined when the core is initialized.

Definition at line 144 of file WriteSLAC.hpp.

Referenced by gather_mesh_information(), write_file(), and WriteSLAC().

Definition at line 148 of file WriteSLAC.hpp.

Referenced by gather_interior_exterior(), write_matsets(), and WriteSLAC().

Definition at line 146 of file WriteSLAC.hpp.

Referenced by gather_mesh_information(), write_file(), and WriteSLAC().

int moab::WriteSLAC::ncFile [private]

Definition at line 140 of file WriteSLAC.hpp.

Referenced by initialize_file(), open_file(), write_file(), write_matsets(), and write_nodes().

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