Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
moab::Skinner Class Reference

Class for constructing and querying skin of a mesh Class for constructing and querying skin of a mesh, defined as the outside lower-dimensional boundary of a mesh or a given set of entities. This class provides options for finding the forward- and reverse-oriented members of the skin. Several methods are available for computing the skin, e.g. using geometric topology sets, vertex-entity adjacencies, or directly from (n-1)-dimensional entities. More...

#include <Skinner.hpp>

+ Collaboration diagram for moab::Skinner:

Public Member Functions

 Skinner (Interface *mdb)
 constructor, takes mdb instance More...
 
 ~Skinner ()
 destructor More...
 
ErrorCode find_geometric_skin (const EntityHandle meshset, Range &forward_target_entities)
 
ErrorCode find_skin (const EntityHandle meshset, const Range &entities, bool get_vertices, Range &output_handles, Range *output_reverse_handles=0, bool create_vert_elem_adjs=false, bool create_skin_elements=true, bool look_for_scd=false)
 will accept entities all of one dimension and return entities of n-1 dimension; NOTE: get_vertices argument controls whether vertices or entities of n-1 dimension are returned, and only one of these is allowed (i.e. this function returns only vertices or (n-1)-dimensional entities, but not both) More...
 
ErrorCode find_skin (const EntityHandle this_set, const EntityHandle *entities, int num_entities, bool get_vertices, Range &output_handles, Range *output_reverse_handles=0, bool create_vert_elem_adjs=false, bool create_skin_elements=true, bool look_for_scd=false)
 will accept entities all of one dimension and return entities of n-1 dimension; NOTE: get_vertices argument controls whether vertices or entities of n-1 dimension are returned, and only one of these is allowed (i.e. this function returns only vertices or (n-1)-dimensional entities, but not both) More...
 
ErrorCode find_skin (const EntityHandle this_set, const Range &entities, int dim, Range &skin_entities, bool create_vert_elem_adjs=false, bool create_skin_elements=true)
 get skin entities of prescribed dimension More...
 
ErrorCode classify_2d_boundary (const Range &boundary, const Range &bar_elements, EntityHandle boundary_edges, EntityHandle inferred_edges, EntityHandle non_manifold_edges, EntityHandle other_edges, int &number_boundary_nodes)
 
ErrorCode classify_2d_boundary (const Range &boundary, const Range &mesh_1d_elements, Range &boundary_edges, Range &inferred_edges, Range &non_manifold_edges, Range &other_edges, int &number_boundary_nodes)
 given a skin of dimension 2, will classify and return edges as boundary, inferred, and non-manifold, and the rest (other) More...
 

Protected Member Functions

ErrorCode initialize ()
 
ErrorCode deinitialize ()
 
ErrorCode find_skin_noadj (const Range &source_entities, Range &forward_target_entities, Range &reverse_target_entities)
 
ErrorCode add_adjacency (EntityHandle entity)
 
void add_adjacency (EntityHandle entity, const EntityHandle *conn, const int num_nodes)
 
ErrorCode remove_adjacency (EntityHandle entity)
 
bool entity_deletable (EntityHandle entity)
 
void find_match (EntityType type, const EntityHandle *conn, const int num_nodes, EntityHandle &match, Skinner::direction &direct)
 
bool connectivity_match (const EntityHandle *conn1, const EntityHandle *conn2, const int num_verts, Skinner::direction &direct)
 
void find_inferred_edges (Range &skin_boundary, Range &candidate_edges, Range &inferred_edges, double reference_angle_degrees)
 
bool has_larger_angle (EntityHandle &entity1, EntityHandle &entity2, double reference_angle_cosine)
 
ErrorCode find_skin_vertices (const EntityHandle this_set, const Range &entities, Range *skin_verts=0, Range *skin_elems=0, Range *rev_elems=0, bool create_if_missing=true, bool corners_only=false)
 Find vertices on the skin of a set of mesh entities. More...
 
ErrorCode find_skin_vertices_1D (Tag tag, const Range &edges, Range &skin_verts)
 Skin edges. More...
 
ErrorCode find_skin_vertices_2D (const EntityHandle this_set, Tag tag, const Range &faces, Range *skin_verts=0, Range *skin_edges=0, Range *reverse_edges=0, bool create_edges=false, bool corners_only=false)
 Skin faces. More...
 
ErrorCode find_skin_vertices_3D (const EntityHandle this_set, Tag tag, const Range &entities, Range *skin_verts=0, Range *skin_faces=0, Range *reverse_faces=0, bool create_faces=false, bool corners_only=false)
 Skin volume mesh. More...
 
ErrorCode create_side (const EntityHandle this_set, EntityHandle element, EntityType side_type, const EntityHandle *side_corners, EntityHandle &side_elem_handle_out)
 
bool edge_reversed (EntityHandle face, const EntityHandle edge_ends[2])
 
bool face_reversed (EntityHandle region, const EntityHandle *face_conn, EntityType face_type)
 
ErrorCode find_skin_scd (const Range &source_entities, bool get_vertices, Range &output_handles, bool create_skin_elements)
 look for structured box comprising source_entities, and if one is found use structured information to find the skin More...
 
ErrorCode skin_box (ScdBox *box, bool get_vertices, Range &output_handles, bool create_skin_elements)
 skin a structured box, taking advantage of structured information More...
 

Protected Attributes

InterfacethisMB
 the MB instance that this works with More...
 
Tag mDeletableMBTag
 
Tag mAdjTag
 
int mTargetDim
 

Private Types

enum  direction { FORWARD = 1 , REVERSE = -1 }
 

Detailed Description

Class for constructing and querying skin of a mesh Class for constructing and querying skin of a mesh, defined as the outside lower-dimensional boundary of a mesh or a given set of entities. This class provides options for finding the forward- and reverse-oriented members of the skin. Several methods are available for computing the skin, e.g. using geometric topology sets, vertex-entity adjacencies, or directly from (n-1)-dimensional entities.

Examples
OptimizeMeshMesquite.cpp.

Definition at line 36 of file Skinner.hpp.

Member Enumeration Documentation

◆ direction

Enumerator
FORWARD 
REVERSE 

Definition at line 39 of file Skinner.hpp.

40  {
41  FORWARD = 1,
42  REVERSE = -1
43  };

Constructor & Destructor Documentation

◆ Skinner()

moab::Skinner::Skinner ( Interface mdb)
inline

constructor, takes mdb instance

Definition at line 55 of file Skinner.hpp.

55 : thisMB( mdb ), mDeletableMBTag( 0 ), mAdjTag( 0 ), mTargetDim( 0 ) {}

◆ ~Skinner()

moab::Skinner::~Skinner ( )

destructor

Definition at line 48 of file Skinner.cpp.

49 {
50  // delete the adjacency tag
51 }

Member Function Documentation

◆ add_adjacency() [1/2]

ErrorCode moab::Skinner::add_adjacency ( EntityHandle  entity)
protected

Definition at line 135 of file Skinner.cpp.

136 {
137  std::vector< EntityHandle >* adj = NULL;
138  const EntityHandle* nodes;
139  int num_nodes;
140  ErrorCode result = thisMB->get_connectivity( entity, nodes, num_nodes, true );
141  MB_CHK_ERR( result );
142  const EntityHandle* iter = std::min_element( nodes, nodes + num_nodes );
143 
144  if( iter == nodes + num_nodes ) return MB_SUCCESS;
145 
146  // add this entity to the node
147  if( thisMB->tag_get_data( mAdjTag, iter, 1, &adj ) == MB_SUCCESS && adj != NULL )
148  {
149  adj->push_back( entity );
150  }
151  // create a new vector and add it
152  else
153  {
154  adj = new std::vector< EntityHandle >;
155  adj->push_back( entity );
156  result = thisMB->tag_set_data( mAdjTag, iter, 1, &adj );
157  MB_CHK_ERR( result );
158  }
159 
160  return MB_SUCCESS;
161 }

References ErrorCode, moab::Interface::get_connectivity(), mAdjTag, MB_CHK_ERR, MB_SUCCESS, moab::Interface::tag_get_data(), moab::Interface::tag_set_data(), and thisMB.

Referenced by classify_2d_boundary(), find_skin_noadj(), and initialize().

◆ add_adjacency() [2/2]

void moab::Skinner::add_adjacency ( EntityHandle  entity,
const EntityHandle conn,
const int  num_nodes 
)
protected

Definition at line 163 of file Skinner.cpp.

164 {
165  std::vector< EntityHandle >* adj = NULL;
166  const EntityHandle* iter = std::min_element( nodes, nodes + num_nodes );
167 
168  if( iter == nodes + num_nodes ) return;
169 
170  // should not be setting adjacency lists in ho-nodes
171  assert( TYPE_FROM_HANDLE( entity ) == MBPOLYGON ||
172  num_nodes == CN::VerticesPerEntity( TYPE_FROM_HANDLE( entity ) ) );
173 
174  // add this entity to the node
175  if( thisMB->tag_get_data( mAdjTag, iter, 1, &adj ) == MB_SUCCESS && adj != NULL )
176  {
177  adj->push_back( entity );
178  }
179  // create a new vector and add it
180  else
181  {
182  adj = new std::vector< EntityHandle >;
183  adj->push_back( entity );
184  thisMB->tag_set_data( mAdjTag, iter, 1, &adj );
185  }
186 }

References mAdjTag, MB_SUCCESS, MBPOLYGON, moab::Interface::tag_get_data(), moab::Interface::tag_set_data(), thisMB, moab::TYPE_FROM_HANDLE(), and moab::CN::VerticesPerEntity().

◆ classify_2d_boundary() [1/2]

ErrorCode moab::Skinner::classify_2d_boundary ( const Range boundary,
const Range bar_elements,
EntityHandle  boundary_edges,
EntityHandle  inferred_edges,
EntityHandle  non_manifold_edges,
EntityHandle  other_edges,
int &  number_boundary_nodes 
)

Definition at line 668 of file Skinner.cpp.

675 {
676  Range bedges, iedges, nmedges, oedges;
677  ErrorCode result =
678  classify_2d_boundary( boundary, bar_elements, bedges, iedges, nmedges, oedges, number_boundary_nodes );
679  MB_CHK_ERR( result );
680 
681  // now set the input meshsets to the output ranges
682  result = thisMB->clear_meshset( &boundary_edges, 1 );
683  MB_CHK_ERR( result );
684  result = thisMB->add_entities( boundary_edges, bedges );
685  MB_CHK_ERR( result );
686 
687  result = thisMB->clear_meshset( &inferred_edges, 1 );
688  MB_CHK_ERR( result );
689  result = thisMB->add_entities( inferred_edges, iedges );
690  MB_CHK_ERR( result );
691 
692  result = thisMB->clear_meshset( &non_manifold_edges, 1 );
693  MB_CHK_ERR( result );
694  result = thisMB->add_entities( non_manifold_edges, nmedges );
695  MB_CHK_ERR( result );
696 
697  result = thisMB->clear_meshset( &other_edges, 1 );
698  MB_CHK_ERR( result );
699  result = thisMB->add_entities( other_edges, oedges );
700  MB_CHK_ERR( result );
701 
702  return MB_SUCCESS;
703 }

References moab::Interface::add_entities(), moab::Interface::clear_meshset(), ErrorCode, MB_CHK_ERR, MB_SUCCESS, and thisMB.

◆ classify_2d_boundary() [2/2]

ErrorCode moab::Skinner::classify_2d_boundary ( const Range boundary,
const Range mesh_1d_elements,
Range boundary_edges,
Range inferred_edges,
Range non_manifold_edges,
Range other_edges,
int &  number_boundary_nodes 
)

given a skin of dimension 2, will classify and return edges as boundary, inferred, and non-manifold, and the rest (other)

Definition at line 705 of file Skinner.cpp.

712 {
713 
714  // clear out the edge lists
715 
716  boundary_edges.clear();
717  inferred_edges.clear();
718  non_manifold_edges.clear();
719  other_edges.clear();
720 
721  number_boundary_nodes = 0;
722 
723  // make sure we have something to work with
724  if( boundary.empty() )
725  {
726  return MB_FAILURE;
727  }
728 
729  // get our working dimensions
730  EntityType type = thisMB->type_from_handle( *( boundary.begin() ) );
731  const int source_dim = CN::Dimension( type );
732 
733  // make sure we can handle the working dimensions
734  if( source_dim != 2 )
735  {
736  return MB_FAILURE;
737  }
738  mTargetDim = source_dim - 1;
739 
740  // initialize
741  initialize();
742 
743  // additional initialization for this routine
744  // define a tag for MBEDGE which counts the occurrences of the edge below
745  // default should be 0 for existing edges, if any
746 
747  Tag count_tag;
748  int default_count = 0;
749  ErrorCode result =
750  thisMB->tag_get_handle( 0, 1, MB_TYPE_INTEGER, count_tag, MB_TAG_DENSE | MB_TAG_CREAT, &default_count );
751  MB_CHK_ERR( result );
752 
753  Range::const_iterator iter, end_iter;
754  end_iter = boundary.end();
755 
756  std::vector< EntityHandle > conn;
757  EntityHandle sub_conn[2];
758  EntityHandle match;
759 
760  Range edge_list;
761  Range boundary_nodes;
762  Skinner::direction direct;
763 
764  EntityType sub_type;
765  int num_edge, num_sub_ent_vert;
766  const short* edge_verts;
767 
768  // now, process each entity in the boundary
769 
770  for( iter = boundary.begin(); iter != end_iter; ++iter )
771  {
772  // get the connectivity of this entity
773  conn.clear();
774  result = thisMB->get_connectivity( &( *iter ), 1, conn, false );
775  assert( MB_SUCCESS == result );
776 
777  // add node handles to boundary_node range
778  std::copy( conn.begin(), conn.begin() + CN::VerticesPerEntity( type ), range_inserter( boundary_nodes ) );
779 
780  type = thisMB->type_from_handle( *iter );
781 
782  // get connectivity of each n-1 dimension entity (edge in this case)
783  const struct CN::ConnMap* conn_map = &( CN::mConnectivityMap[type][0] );
784  num_edge = CN::NumSubEntities( type, 1 );
785  for( int i = 0; i < num_edge; i++ )
786  {
787  edge_verts = CN::SubEntityVertexIndices( type, 1, i, sub_type, num_sub_ent_vert );
788  assert( sub_type == MBEDGE && num_sub_ent_vert == 2 );
789  sub_conn[0] = conn[edge_verts[0]];
790  sub_conn[1] = conn[edge_verts[1]];
791  int num_sub_nodes = conn_map->num_corners_per_sub_element[i];
792 
793  // see if we can match this connectivity with
794  // an existing entity
795  find_match( MBEDGE, sub_conn, num_sub_nodes, match, direct );
796 
797  // if there is no match, create a new entity
798  if( match == 0 )
799  {
800  EntityHandle tmphndl = 0;
801  int indices[MAX_SUB_ENTITY_VERTICES];
802  EntityType new_type;
803  int num_new_nodes;
804  CN::SubEntityNodeIndices( type, conn.size(), 1, i, new_type, num_new_nodes, indices );
805  for( int j = 0; j < num_new_nodes; j++ )
806  sub_conn[j] = conn[indices[j]];
807 
808  result = thisMB->create_element( new_type, sub_conn, num_new_nodes, tmphndl );
809  assert( MB_SUCCESS == result );
810  add_adjacency( tmphndl, sub_conn, num_sub_nodes );
811  // target_entities.insert(tmphndl);
812  edge_list.insert( tmphndl );
813  int count;
814  result = thisMB->tag_get_data( count_tag, &tmphndl, 1, &count );
815  assert( MB_SUCCESS == result );
816  count++;
817  result = thisMB->tag_set_data( count_tag, &tmphndl, 1, &count );
818  assert( MB_SUCCESS == result );
819  }
820  else
821  {
822  // We found a match, we must increment the count on the match
823  int count;
824  result = thisMB->tag_get_data( count_tag, &match, 1, &count );
825  assert( MB_SUCCESS == result );
826  count++;
827  result = thisMB->tag_set_data( count_tag, &match, 1, &count );
828  assert( MB_SUCCESS == result );
829 
830  // if the entity is not deletable, it was pre-existing in
831  // the database. We therefore may need to add it to the
832  // edge_list. Since it will not hurt the range, we add
833  // whether it was added before or not
834  if( !entity_deletable( match ) )
835  {
836  edge_list.insert( match );
837  }
838  }
839  }
840  }
841 
842  // Any bar elements in the model should be classified separately
843  // If the element is in the skin edge_list, then it should be put in
844  // the non-manifold edge list. Edges not in the edge_list are stand-alone
845  // bars, and we make them simply boundary elements
846 
847  if( !bar_elements.empty() )
848  {
849  Range::iterator bar_iter;
850  for( iter = bar_elements.begin(); iter != bar_elements.end(); ++iter )
851  {
852  EntityHandle handle = *iter;
853  bar_iter = edge_list.find( handle );
854  if( bar_iter != edge_list.end() )
855  {
856  // it is in the list, erase it and put in non-manifold list
857  edge_list.erase( bar_iter );
858  non_manifold_edges.insert( handle );
859  }
860  else
861  {
862  // not in the edge list, make it a boundary edge
863  boundary_edges.insert( handle );
864  }
865  }
866  }
867 
868  // now all edges should be classified. Go through the edge_list,
869  // and put all in the appropriate lists
870 
871  Range::iterator edge_iter, edge_end_iter;
872  edge_end_iter = edge_list.end();
873  int count;
874  for( edge_iter = edge_list.begin(); edge_iter != edge_end_iter; ++edge_iter )
875  {
876  // check the count_tag
877  result = thisMB->tag_get_data( count_tag, &( *edge_iter ), 1, &count );
878  assert( MB_SUCCESS == result );
879  if( count == 1 )
880  {
881  boundary_edges.insert( *edge_iter );
882  }
883  else if( count == 2 )
884  {
885  other_edges.insert( *edge_iter );
886  }
887  else
888  {
889  non_manifold_edges.insert( *edge_iter );
890  }
891  }
892 
893  // find the inferred edges from the other_edge_list
894 
895  double min_angle_degrees = 20.0;
896  find_inferred_edges( const_cast< Range& >( boundary ), other_edges, inferred_edges, min_angle_degrees );
897 
898  // we now want to remove the inferred_edges from the other_edges
899 
900  Range temp_range;
901 
902  std::set_difference( other_edges.begin(), other_edges.end(), inferred_edges.begin(), inferred_edges.end(),
903  range_inserter( temp_range ), std::less< EntityHandle >() );
904 
905  other_edges = temp_range;
906 
907  // get rid of count tag and deinitialize
908 
909  result = thisMB->tag_delete( count_tag );
910  assert( MB_SUCCESS == result );
911  deinitialize();
912 
913  // set the node count
914  number_boundary_nodes = boundary_nodes.size();
915 
916  return MB_SUCCESS;
917 }

References add_adjacency(), moab::Range::begin(), moab::Range::clear(), moab::Interface::create_element(), deinitialize(), moab::CN::Dimension(), moab::Range::empty(), moab::Range::end(), entity_deletable(), moab::Range::erase(), ErrorCode, moab::Range::find(), find_inferred_edges(), find_match(), moab::Interface::get_connectivity(), initialize(), moab::Range::insert(), moab::MAX_SUB_ENTITY_VERTICES, MB_CHK_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_INTEGER, MBEDGE, moab::CN::mConnectivityMap, mTargetDim, moab::CN::ConnMap::num_corners_per_sub_element, moab::CN::NumSubEntities(), moab::Range::size(), moab::CN::SubEntityNodeIndices(), moab::CN::SubEntityVertexIndices(), moab::Interface::tag_delete(), moab::Interface::tag_get_data(), moab::Interface::tag_get_handle(), moab::Interface::tag_set_data(), thisMB, moab::Interface::type_from_handle(), and moab::CN::VerticesPerEntity().

◆ connectivity_match()

bool moab::Skinner::connectivity_match ( const EntityHandle conn1,
const EntityHandle conn2,
const int  num_verts,
Skinner::direction direct 
)
protected

Definition at line 590 of file Skinner.cpp.

594 {
595  const EntityHandle* iter = std::find( conn2, conn2 + num_verts, conn1[0] );
596  if( iter == conn2 + num_verts ) return false;
597 
598  bool they_match = true;
599 
600  int i;
601  unsigned int j = iter - conn2;
602 
603  // first compare forward
604  for( i = 1; i < num_verts; ++i )
605  {
606  if( conn1[i] != conn2[( j + i ) % num_verts] )
607  {
608  they_match = false;
609  break;
610  }
611  }
612 
613  if( they_match == true )
614  {
615  // need to check for reversed edges here
616  direct = ( num_verts == 2 && j ) ? REVERSE : FORWARD;
617  return true;
618  }
619 
620  they_match = true;
621 
622  // then compare reverse
623  j += num_verts;
624  for( i = 1; i < num_verts; )
625  {
626  if( conn1[i] != conn2[( j - i ) % num_verts] )
627  {
628  they_match = false;
629  break;
630  }
631  ++i;
632  }
633  if( they_match )
634  {
635  direct = REVERSE;
636  }
637  return they_match;
638 }

References FORWARD, and REVERSE.

Referenced by find_match().

◆ create_side()

ErrorCode moab::Skinner::create_side ( const EntityHandle  this_set,
EntityHandle  element,
EntityType  side_type,
const EntityHandle side_corners,
EntityHandle side_elem_handle_out 
)
protected

Definition at line 1452 of file Skinner.cpp.

1457 {
1458  const int max_side = 9;
1459  const EntityHandle* conn;
1460  int len, side_len, side, sense, offset, indices[max_side];
1461  ErrorCode rval;
1462  EntityType type = TYPE_FROM_HANDLE( elem ), tmp_type;
1463  const int ncorner = CN::VerticesPerEntity( side_type );
1464  const int d = CN::Dimension( side_type );
1465  std::vector< EntityHandle > storage;
1466 
1467  // Get the connectivity of the parent element
1468  rval = thisMB->get_connectivity( elem, conn, len, false, &storage );
1469  if( MB_SUCCESS != rval ) return rval;
1470 
1471  // treat separately MBPOLYGON; we want to create the edge in the
1472  // forward sense always ; so figure out the sense first, then get out
1473  if( MBPOLYGON == type && 1 == d && MBEDGE == side_type )
1474  {
1475  // first find the first vertex in the conn list
1476  int i = 0;
1477  for( i = 0; i < len; i++ )
1478  {
1479  if( conn[i] == side_conn[0] ) break;
1480  }
1481  if( len == i ) return MB_FAILURE; // not found, big error
1482  // now, what if the polygon is padded?
1483  // the previous index is fine always. but the next one could be trouble :(
1484  int prevIndex = ( i + len - 1 ) % len;
1485  int nextIndex = ( i + 1 ) % len;
1486  // if the next index actually point to the same node, as current, it means it is padded
1487  if( conn[nextIndex] == conn[i] )
1488  {
1489  // it really means we are at the end of proper nodes, the last nodes are repeated, so it
1490  // should be the first node
1491  nextIndex = 0; // this is the first node!
1492  }
1493  EntityHandle conn2[2] = { side_conn[0], side_conn[1] };
1494  if( conn[prevIndex] == side_conn[1] )
1495  {
1496  // reverse, so the edge will be forward
1497  conn2[0] = side_conn[1];
1498  conn2[1] = side_conn[0];
1499  }
1500  else if( conn[nextIndex] != side_conn[1] )
1501  return MB_FAILURE; // it is not adjacent to the polygon
1502 
1503  MB_CHK_ERR( thisMB->create_element( MBEDGE, conn2, 2, side_elem ) );
1504  if( this_set )
1505  {
1506  MB_CHK_ERR( thisMB->add_entities( this_set, &side_elem, 1 ) );
1507  }
1508  return MB_SUCCESS;
1509  }
1510  // Find which side we are creating and get indices of all nodes
1511  // (including higher-order, if any.)
1512  CN::SideNumber( type, conn, side_conn, ncorner, d, side, sense, offset );
1513  CN::SubEntityNodeIndices( type, len, d, side, tmp_type, side_len, indices );
1514  assert( side_len <= max_side );
1515  assert( side_type == tmp_type );
1516 
1517  // NOTE: re-create conn array even when no higher-order nodes
1518  // because we want it to always be forward with respect
1519  // to the side ordering.
1520  EntityHandle side_conn_full[max_side];
1521  for( int i = 0; i < side_len; ++i )
1522  side_conn_full[i] = conn[indices[i]];
1523 
1524  MB_CHK_ERR( thisMB->create_element( side_type, side_conn_full, side_len, side_elem ) );
1525  if( this_set )
1526  {
1527  MB_CHK_ERR( thisMB->add_entities( this_set, &side_elem, 1 ) );
1528  }
1529  return MB_SUCCESS;
1530  ;
1531 }

References moab::CN::Dimension(), ErrorCode, MB_CHK_ERR, MB_SUCCESS, MBEDGE, MBPOLYGON, moab::CN::SideNumber(), moab::CN::SubEntityNodeIndices(), moab::TYPE_FROM_HANDLE(), and moab::CN::VerticesPerEntity().

◆ deinitialize()

ErrorCode moab::Skinner::deinitialize ( )
protected

Definition at line 100 of file Skinner.cpp.

101 {
102  ErrorCode result;
103  if( 0 != mDeletableMBTag )
104  {
105  result = thisMB->tag_delete( mDeletableMBTag );
106  mDeletableMBTag = 0;
107  MB_CHK_ERR( result );
108  }
109 
110  // remove the adjacency tag
111  std::vector< std::vector< EntityHandle >* > adj_arr;
112  std::vector< std::vector< EntityHandle >* >::iterator i;
113  if( 0 != mAdjTag )
114  {
115  for( EntityType t = MBVERTEX; t != MBMAXTYPE; ++t )
116  {
117  Range entities;
118  result = thisMB->get_entities_by_type_and_tag( 0, t, &mAdjTag, 0, 1, entities );
119  MB_CHK_ERR( result );
120  adj_arr.resize( entities.size() );
121  result = thisMB->tag_get_data( mAdjTag, entities, &adj_arr[0] );
122  MB_CHK_ERR( result );
123  for( i = adj_arr.begin(); i != adj_arr.end(); ++i )
124  delete *i;
125  }
126 
127  result = thisMB->tag_delete( mAdjTag );
128  mAdjTag = 0;
129  MB_CHK_ERR( result );
130  }
131 
132  return MB_SUCCESS;
133 }

References ErrorCode, moab::Interface::get_entities_by_type_and_tag(), mAdjTag, MB_CHK_ERR, MB_SUCCESS, MBMAXTYPE, MBVERTEX, mDeletableMBTag, moab::Range::size(), moab::Interface::tag_delete(), moab::Interface::tag_get_data(), and thisMB.

Referenced by classify_2d_boundary(), and find_skin_noadj().

◆ edge_reversed()

bool moab::Skinner::edge_reversed ( EntityHandle  face,
const EntityHandle  edge_ends[2] 
)
protected

Definition at line 1535 of file Skinner.cpp.

1536 {
1537  const EntityHandle* conn;
1538  int len, idx;
1539  ErrorCode rval = thisMB->get_connectivity( face, conn, len, true );
1540  if( MB_SUCCESS != rval )
1541  {
1542  assert( false );
1543  return false;
1544  }
1545  idx = std::find( conn, conn + len, edge_ends[0] ) - conn;
1546  if( idx == len )
1547  {
1548  assert( false );
1549  return false;
1550  }
1551  return ( edge_ends[1] == conn[( idx + len - 1 ) % len] );
1552 }

References ErrorCode, and MB_SUCCESS.

◆ entity_deletable()

bool moab::Skinner::entity_deletable ( EntityHandle  entity)
protected

Definition at line 659 of file Skinner.cpp.

660 {
661  unsigned char deletable = 0;
662  ErrorCode result = thisMB->tag_get_data( mDeletableMBTag, &entity, 1, &deletable );
663  assert( MB_SUCCESS == result );
664  if( MB_SUCCESS == result && deletable == 1 ) return false;
665  return true;
666 }

References ErrorCode, MB_SUCCESS, mDeletableMBTag, moab::Interface::tag_get_data(), and thisMB.

Referenced by classify_2d_boundary(), and find_skin_noadj().

◆ face_reversed()

bool moab::Skinner::face_reversed ( EntityHandle  region,
const EntityHandle face_conn,
EntityType  face_type 
)
protected

Definition at line 1557 of file Skinner.cpp.

1558 {
1559  const EntityHandle* conn;
1560  int len, side, sense, offset;
1561  ErrorCode rval = thisMB->get_connectivity( region, conn, len, true );
1562  if( MB_SUCCESS != rval )
1563  {
1564  assert( false );
1565  return false;
1566  }
1567  short r = CN::SideNumber( TYPE_FROM_HANDLE( region ), conn, face_corners, CN::VerticesPerEntity( face_type ),
1568  CN::Dimension( face_type ), side, sense, offset );
1569  assert( 0 == r );
1570  return ( !r && sense == -1 );
1571 }

References moab::CN::Dimension(), ErrorCode, MB_SUCCESS, moab::CN::SideNumber(), moab::TYPE_FROM_HANDLE(), and moab::CN::VerticesPerEntity().

◆ find_geometric_skin()

ErrorCode moab::Skinner::find_geometric_skin ( const EntityHandle  meshset,
Range forward_target_entities 
)

Definition at line 188 of file Skinner.cpp.

189 {
190  // attempts to find whole model skin, using geom topo sets first then
191  // normal find_skin function
192  bool debug = true;
193 
194  // look for geom topo sets
195  Tag geom_tag;
196  ErrorCode result =
198 
199  if( MB_SUCCESS != result ) return result;
200 
201  // get face sets (dimension = 2)
202  Range face_sets;
203  int two = 2;
204  const void* two_ptr = &two;
205  result = thisMB->get_entities_by_type_and_tag( meshset, MBENTITYSET, &geom_tag, &two_ptr, 1, face_sets );
206 
207  Range::iterator it;
208  if( MB_SUCCESS != result )
209  return result;
210  else if( face_sets.empty() )
211  return MB_ENTITY_NOT_FOUND;
212 
213  // ok, we have face sets; use those to determine skin
214  Range skin_sets;
215  if( debug ) std::cout << "Found " << face_sets.size() << " face sets total..." << std::endl;
216 
217  for( it = face_sets.begin(); it != face_sets.end(); ++it )
218  {
219  int num_parents;
220  result = thisMB->num_parent_meshsets( *it, &num_parents );
221  if( MB_SUCCESS != result )
222  return result;
223  else if( num_parents == 1 )
224  skin_sets.insert( *it );
225  }
226 
227  if( debug ) std::cout << "Found " << skin_sets.size() << " 1-parent face sets..." << std::endl;
228 
229  if( skin_sets.empty() ) return MB_FAILURE;
230 
231  // ok, we have the shell; gather up the elements, putting them all in forward for now
232  for( it = skin_sets.begin(); it != skin_sets.end(); ++it )
233  {
234  result = thisMB->get_entities_by_handle( *it, forward_target_entities, true );
235  if( MB_SUCCESS != result ) return result;
236  }
237 
238  return result;
239 }

References moab::Range::begin(), moab::debug, moab::Range::empty(), moab::Range::end(), ErrorCode, GEOM_DIMENSION_TAG_NAME, moab::Interface::get_entities_by_handle(), moab::Interface::get_entities_by_type_and_tag(), moab::Range::insert(), MB_ENTITY_NOT_FOUND, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_SPARSE, MB_TYPE_INTEGER, MBENTITYSET, moab::Interface::num_parent_meshsets(), moab::Range::size(), moab::Interface::tag_get_handle(), and thisMB.

◆ find_inferred_edges()

void moab::Skinner::find_inferred_edges ( Range skin_boundary,
Range candidate_edges,
Range inferred_edges,
double  reference_angle_degrees 
)
protected

Definition at line 919 of file Skinner.cpp.

923 {
924 
925  // mark all the entities in the skin boundary
926  Tag mark_tag;
927  ErrorCode result = thisMB->tag_get_handle( 0, 1, MB_TYPE_BIT, mark_tag, MB_TAG_CREAT );
928  assert( MB_SUCCESS == result );
929  unsigned char bit = true;
930  result = thisMB->tag_clear_data( mark_tag, skin_boundary, &bit );
931  assert( MB_SUCCESS == result );
932 
933  // find the cosine of the reference angle
934 
935  double reference_cosine = cos( reference_angle_degrees * SKINNER_PI / 180.0 );
936 
937  // check all candidate edges for an angle greater than the minimum
938 
939  Range::iterator iter, end_iter = candidate_edges.end();
940  std::vector< EntityHandle > adjacencies;
941  std::vector< EntityHandle >::iterator adj_iter;
942  EntityHandle face[2];
943 
944  for( iter = candidate_edges.begin(); iter != end_iter; ++iter )
945  {
946 
947  // get the 2D elements connected to this edge
948  adjacencies.clear();
949  result = thisMB->get_adjacencies( &( *iter ), 1, 2, false, adjacencies );
950  if( MB_SUCCESS != result ) continue;
951 
952  // there should be exactly two, that is why the edge is classified as nonBoundary
953  // and manifold
954 
955  int faces_found = 0;
956  for( adj_iter = adjacencies.begin(); adj_iter != adjacencies.end() && faces_found < 2; ++adj_iter )
957  {
958  // we need to find two of these which are in the skin
959  unsigned char is_marked = 0;
960  result = thisMB->tag_get_data( mark_tag, &( *adj_iter ), 1, &is_marked );
961  assert( MB_SUCCESS == result );
962  if( is_marked )
963  {
964  face[faces_found] = *adj_iter;
965  faces_found++;
966  }
967  }
968 
969  // assert(faces_found == 2 || faces_found == 0);
970  if( 2 != faces_found ) continue;
971 
972  // see if the two entities have a sufficient angle
973 
974  if( has_larger_angle( face[0], face[1], reference_cosine ) )
975  {
976  inferred_edges.insert( *iter );
977  }
978  }
979 
980  result = thisMB->tag_delete( mark_tag );
981  assert( MB_SUCCESS == result );
982 }

References moab::Range::begin(), moab::Range::end(), ErrorCode, moab::Interface::get_adjacencies(), has_larger_angle(), moab::Range::insert(), MB_SUCCESS, MB_TAG_CREAT, MB_TYPE_BIT, SKINNER_PI, moab::Interface::tag_clear_data(), moab::Interface::tag_delete(), moab::Interface::tag_get_data(), moab::Interface::tag_get_handle(), and thisMB.

Referenced by classify_2d_boundary().

◆ find_match()

void moab::Skinner::find_match ( EntityType  type,
const EntityHandle conn,
const int  num_nodes,
EntityHandle match,
Skinner::direction direct 
)
protected

Definition at line 540 of file Skinner.cpp.

545 {
546  match = 0;
547 
548  if( type == MBVERTEX )
549  {
550  match = *conn;
551  direct = FORWARD;
552  return;
553  }
554 
555  const EntityHandle* iter = std::min_element( conn, conn + num_nodes );
556 
557  std::vector< EntityHandle >* adj = NULL;
558 
559  ErrorCode result = thisMB->tag_get_data( mAdjTag, iter, 1, &adj );
560  if( result == MB_FAILURE || adj == NULL )
561  {
562  return;
563  }
564 
565  std::vector< EntityHandle >::iterator jter, end_jter;
566  end_jter = adj->end();
567 
568  const EntityHandle* tmp;
569  int num_verts;
570 
571  for( jter = adj->begin(); jter != end_jter; ++jter )
572  {
573  EntityType tmp_type;
574  tmp_type = thisMB->type_from_handle( *jter );
575 
576  if( type != tmp_type ) continue;
577 
578  result = thisMB->get_connectivity( *jter, tmp, num_verts, false );
579  assert( MB_SUCCESS == result && num_verts >= CN::VerticesPerEntity( type ) );
580  // FIXME: connectivity_match appears to work only for linear elements,
581  // so ignore higher-order nodes.
582  if( connectivity_match( conn, tmp, CN::VerticesPerEntity( type ), direct ) )
583  {
584  match = *jter;
585  break;
586  }
587  }
588 }

References connectivity_match(), ErrorCode, FORWARD, moab::Interface::get_connectivity(), mAdjTag, MB_SUCCESS, MBVERTEX, moab::Interface::tag_get_data(), thisMB, moab::Interface::type_from_handle(), and moab::CN::VerticesPerEntity().

Referenced by classify_2d_boundary(), and find_skin_noadj().

◆ find_skin() [1/3]

ErrorCode moab::Skinner::find_skin ( const EntityHandle  meshset,
const Range entities,
bool  get_vertices,
Range output_handles,
Range output_reverse_handles = 0,
bool  create_vert_elem_adjs = false,
bool  create_skin_elements = true,
bool  look_for_scd = false 
)

will accept entities all of one dimension and return entities of n-1 dimension; NOTE: get_vertices argument controls whether vertices or entities of n-1 dimension are returned, and only one of these is allowed (i.e. this function returns only vertices or (n-1)-dimensional entities, but not both)

Parameters
entitiesThe elements for which to find the skin
get_verticesIf true, vertices on the skin are returned in the range, otherwise elements are returned
output_handlesRange holding skin entities returned
output_reverse_handlesRange holding entities on skin which are reversed wrt entities
create_vert_elem_adjsIf true, this function will cause vertex-element adjacencies to be generated
create_skin_elementsIf true, this function will cause creation of skin entities, otherwise only skin entities already extant will be returned

Definition at line 241 of file Skinner.cpp.

249 {
250  if( source_entities.empty() ) return MB_SUCCESS;
251 
252  if( look_for_scd )
253  {
254  ErrorCode rval = find_skin_scd( source_entities, get_vertices, output_handles, create_skin_elements );
255  // if it returns success, it's all scd, and we don't need to do anything more
256  if( MB_SUCCESS == rval ) return rval;
257  }
258 
259  Core* this_core = dynamic_cast< Core* >( thisMB );
260  if( this_core && create_vert_elem_adjs && !this_core->a_entity_factory()->vert_elem_adjacencies() )
261  this_core->a_entity_factory()->create_vert_elem_adjacencies();
262 
263  return find_skin_vertices( meshset, source_entities, get_vertices ? &output_handles : 0,
264  get_vertices ? 0 : &output_handles, output_reverse_handles, create_skin_elements );
265 }

References moab::Core::a_entity_factory(), moab::AEntityFactory::create_vert_elem_adjacencies(), moab::Range::empty(), ErrorCode, find_skin_scd(), find_skin_vertices(), MB_SUCCESS, thisMB, and moab::AEntityFactory::vert_elem_adjacencies().

Referenced by MetisPartitioner::assemble_taggedsets_graph(), moab::ReadRTT::build_moab(), moab::GeomTopoTool::check_model(), moab::TempestRemapper::ComputeOverlapMesh(), moab::ParallelComm::create_interface_sets(), DeformMeshRemap::execute(), find_skin(), moab::GeomTopoTool::geometrize_surface_set(), get_imesh_mesh(), moab::LloydSmoother::initialize(), main(), moab::MergeMesh::merge_entities(), moab::MergeMesh::merge_higher_dimensions(), moab::ParallelMergeMesh::PopulateMySkinEnts(), moab::ParallelComm::resolve_shared_ents(), tag_depth(), and moab::WriteCCMIO::write_cells_and_faces().

◆ find_skin() [2/3]

ErrorCode moab::Skinner::find_skin ( const EntityHandle  this_set,
const EntityHandle entities,
int  num_entities,
bool  get_vertices,
Range output_handles,
Range output_reverse_handles = 0,
bool  create_vert_elem_adjs = false,
bool  create_skin_elements = true,
bool  look_for_scd = false 
)
inline

will accept entities all of one dimension and return entities of n-1 dimension; NOTE: get_vertices argument controls whether vertices or entities of n-1 dimension are returned, and only one of these is allowed (i.e. this function returns only vertices or (n-1)-dimensional entities, but not both)

Parameters
entitiesPointer to elements for which to find the skin
num_entitiesNumber of entities in vector
get_verticesIf true, vertices on the skin are returned in the range, otherwise elements are returned
output_handlesRange holding skin entities returned
output_reverse_handlesRange holding entities on skin which are reversed wrt entities
create_vert_elem_adjsIf true, this function will cause vertex-element adjacencies to be generated
create_skin_elementsIf true, this function will cause creation of skin entities, otherwise only skin entities already extant will be returned

Definition at line 286 of file Skinner.hpp.

295 {
296  Range ents;
297  std::copy( entities, entities + num_entities, range_inserter( ents ) );
298  return find_skin( this_set, ents, get_vertices, output_handles, output_reverse_handles, create_vert_elem_adjs,
299  create_skin_elements, look_for_scd );
300 }

References find_skin().

◆ find_skin() [3/3]

ErrorCode moab::Skinner::find_skin ( const EntityHandle  this_set,
const Range entities,
int  dim,
Range skin_entities,
bool  create_vert_elem_adjs = false,
bool  create_skin_elements = true 
)

get skin entities of prescribed dimension

Parameters
entitiesThe elements for which to find the skin
dimDimension of skin entities requested
skin_entitiesRange holding skin entities returned
create_vert_elem_adjsIf true, this function will cause vertex-element adjacencies to be generated

Definition at line 1004 of file Skinner.cpp.

1010 {
1011  Range tmp_skin;
1012  ErrorCode result =
1013  find_skin( this_set, entities, ( dim == 0 ), tmp_skin, 0, create_vert_elem_adjs, create_skin_elements );
1014  if( MB_SUCCESS != result || tmp_skin.empty() ) return result;
1015 
1016  if( tmp_skin.all_of_dimension( dim ) )
1017  {
1018  if( skin_entities.empty() )
1019  skin_entities.swap( tmp_skin );
1020  else
1021  skin_entities.merge( tmp_skin );
1022  }
1023  else
1024  {
1025  result = thisMB->get_adjacencies( tmp_skin, dim, create_skin_elements, skin_entities, Interface::UNION );
1026  MB_CHK_ERR( result );
1027  if( this_set ) result = thisMB->add_entities( this_set, skin_entities );
1028  }
1029 
1030  return result;
1031 }

References moab::Interface::add_entities(), moab::Range::all_of_dimension(), moab::Range::empty(), ErrorCode, find_skin(), moab::Interface::get_adjacencies(), MB_CHK_ERR, MB_SUCCESS, moab::Range::merge(), moab::Range::swap(), thisMB, and moab::Interface::UNION.

◆ find_skin_noadj()

ErrorCode moab::Skinner::find_skin_noadj ( const Range source_entities,
Range forward_target_entities,
Range reverse_target_entities 
)
protected

use_adjs &&

use_adjs &&

Definition at line 394 of file Skinner.cpp.

398 {
399  if( source_entities.empty() ) return MB_FAILURE;
400 
401  // get our working dimensions
402  EntityType type = thisMB->type_from_handle( *( source_entities.begin() ) );
403  const int source_dim = CN::Dimension( type );
404  mTargetDim = source_dim - 1;
405 
406  // make sure we can handle the working dimensions
407  if( mTargetDim < 0 || source_dim > 3 ) return MB_FAILURE;
408 
409  initialize();
410 
411  Range::const_iterator iter, end_iter;
412  end_iter = source_entities.end();
413  const EntityHandle* conn;
414  EntityHandle match;
415 
416  direction direct;
417  ErrorCode result;
418  // assume we'll never have more than 32 vertices on a facet (checked
419  // with assert later)
420  EntityHandle sub_conn[32];
421  std::vector< EntityHandle > tmp_conn_vec;
422  int num_nodes, num_sub_nodes, num_sides;
423  int sub_indices[32]; // Also, assume that no polygon has more than 32 nodes
424  // we could increase that, but we will not display it right in visit moab h5m , anyway
425  EntityType sub_type;
426 
427  // for each source entity
428  for( iter = source_entities.begin(); iter != end_iter; ++iter )
429  {
430  // get the connectivity of this entity
431  int actual_num_nodes_polygon = 0;
432  result = thisMB->get_connectivity( *iter, conn, num_nodes, false, &tmp_conn_vec );
433  if( MB_SUCCESS != result ) return result;
434 
435  type = thisMB->type_from_handle( *iter );
436  Range::iterator seek_iter;
437 
438  // treat separately polygons (also, polyhedra will need special handling)
439  if( MBPOLYGON == type )
440  {
441  // treat padded polygons, if existing; count backwards, see how many of the last nodes
442  // are repeated assume connectivity is fine, otherwise we could be in trouble
443  actual_num_nodes_polygon = num_nodes;
444  while( actual_num_nodes_polygon >= 3 &&
445  conn[actual_num_nodes_polygon - 1] == conn[actual_num_nodes_polygon - 2] )
446  actual_num_nodes_polygon--;
447  num_sides = actual_num_nodes_polygon;
448  sub_type = MBEDGE;
449  num_sub_nodes = 2;
450  }
451  else // get connectivity of each n-1 dimension entity
452  num_sides = CN::NumSubEntities( type, mTargetDim );
453  for( int i = 0; i < num_sides; i++ )
454  {
455  if( MBPOLYGON == type )
456  {
457  sub_conn[0] = conn[i];
458  sub_conn[1] = conn[i + 1];
459  if( i + 1 == actual_num_nodes_polygon ) sub_conn[1] = conn[0];
460  }
461  else
462  {
463  CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, sub_type, num_sub_nodes, sub_indices );
464  assert( (size_t)num_sub_nodes <= sizeof( sub_indices ) / sizeof( sub_indices[0] ) );
465  for( int j = 0; j < num_sub_nodes; j++ )
466  sub_conn[j] = conn[sub_indices[j]];
467  }
468 
469  // see if we can match this connectivity with
470  // an existing entity
471  find_match( sub_type, sub_conn, num_sub_nodes, match, direct );
472 
473  // if there is no match, create a new entity
474  if( match == 0 )
475  {
476  EntityHandle tmphndl = 0;
477  int indices[MAX_SUB_ENTITY_VERTICES];
478  EntityType new_type;
479  int num_new_nodes;
480  if( MBPOLYGON == type )
481  {
482  new_type = MBEDGE;
483  num_new_nodes = 2;
484  }
485  else
486  {
487  CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, new_type, num_new_nodes, indices );
488  for( int j = 0; j < num_new_nodes; j++ )
489  sub_conn[j] = conn[indices[j]];
490  }
491  result = thisMB->create_element( new_type, sub_conn, num_new_nodes, tmphndl );
492  assert( MB_SUCCESS == result );
493  add_adjacency( tmphndl, sub_conn, CN::VerticesPerEntity( new_type ) );
494  forward_target_entities.insert( tmphndl );
495  }
496  // if there is a match, delete the matching entity
497  // if we can.
498  else
499  {
500  if( ( seek_iter = forward_target_entities.find( match ) ) != forward_target_entities.end() )
501  {
502  forward_target_entities.erase( seek_iter );
503  remove_adjacency( match );
504  if( /*!use_adjs &&*/ entity_deletable( match ) )
505  {
506  result = thisMB->delete_entities( &match, 1 );
507  assert( MB_SUCCESS == result );
508  }
509  }
510  else if( ( seek_iter = reverse_target_entities.find( match ) ) != reverse_target_entities.end() )
511  {
512  reverse_target_entities.erase( seek_iter );
513  remove_adjacency( match );
514  if( /*!use_adjs &&*/ entity_deletable( match ) )
515  {
516  result = thisMB->delete_entities( &match, 1 );
517  assert( MB_SUCCESS == result );
518  }
519  }
520  else
521  {
522  if( direct == FORWARD )
523  {
524  forward_target_entities.insert( match );
525  }
526  else
527  {
528  reverse_target_entities.insert( match );
529  }
530  }
531  }
532  }
533  }
534 
535  deinitialize();
536 
537  return MB_SUCCESS;
538 }

References add_adjacency(), moab::Range::begin(), moab::Interface::create_element(), deinitialize(), moab::Interface::delete_entities(), moab::CN::Dimension(), moab::Range::empty(), moab::Range::end(), entity_deletable(), moab::Range::erase(), ErrorCode, moab::Range::find(), find_match(), FORWARD, moab::Interface::get_connectivity(), initialize(), moab::Range::insert(), moab::MAX_SUB_ENTITY_VERTICES, MB_SUCCESS, MBEDGE, MBPOLYGON, mTargetDim, moab::CN::NumSubEntities(), remove_adjacency(), moab::CN::SubEntityNodeIndices(), thisMB, moab::Interface::type_from_handle(), and moab::CN::VerticesPerEntity().

◆ find_skin_scd()

ErrorCode moab::Skinner::find_skin_scd ( const Range source_entities,
bool  get_vertices,
Range output_handles,
bool  create_skin_elements 
)
protected

look for structured box comprising source_entities, and if one is found use structured information to find the skin

Definition at line 267 of file Skinner.cpp.

271 {
272  // get the scd interface and check if it's been initialized
273  ScdInterface* scdi = NULL;
274  ErrorCode rval = thisMB->query_interface( scdi );
275  if( !scdi ) return MB_FAILURE;
276 
277  // ok, there's scd mesh; see if the entities passed in are all in a scd box
278  // a box needs to be wholly included in entities for this to work
279  std::vector< ScdBox* > boxes, myboxes;
280  Range myrange;
281  rval = scdi->find_boxes( boxes );
282  if( MB_SUCCESS != rval ) return rval;
283  for( std::vector< ScdBox* >::iterator bit = boxes.begin(); bit != boxes.end(); ++bit )
284  {
285  Range belems( ( *bit )->start_element(), ( *bit )->start_element() + ( *bit )->num_elements() - 1 );
286  if( source_entities.contains( belems ) )
287  {
288  myboxes.push_back( *bit );
289  myrange.merge( belems );
290  }
291  }
292  if( myboxes.empty() || myrange.size() != source_entities.size() ) return MB_FAILURE;
293 
294  // ok, we're all structured; get the skin for each box
295  for( std::vector< ScdBox* >::iterator bit = boxes.begin(); bit != boxes.end(); ++bit )
296  {
297  rval = skin_box( *bit, get_vertices, output_handles, create_skin_elements );
298  if( MB_SUCCESS != rval ) return rval;
299  }
300 
301  return MB_SUCCESS;
302 }

References moab::Range::contains(), ErrorCode, moab::ScdInterface::find_boxes(), MB_SUCCESS, moab::Range::merge(), moab::Interface::query_interface(), moab::Range::size(), skin_box(), and thisMB.

Referenced by find_skin().

◆ find_skin_vertices()

ErrorCode moab::Skinner::find_skin_vertices ( const EntityHandle  this_set,
const Range entities,
Range skin_verts = 0,
Range skin_elems = 0,
Range rev_elems = 0,
bool  create_if_missing = true,
bool  corners_only = false 
)
protected

Find vertices on the skin of a set of mesh entities.

Parameters
entitiesThe elements for which to find the skin. Range may NOT contain vertices, polyhedra, or entity sets. All elements in range must be of the same dimension.
skin_vertsOutput: the vertices on the skin.
skin_elemsOptional output: elements representing sides of entities that are on the skin
create_if_missingIf skin_elemts is non-null and this is true, create new elements representing the sides of entities on the skin. If this is false, skin_elems will contain only those skin elements that already exist.

Definition at line 1033 of file Skinner.cpp.

1040 {
1041  ErrorCode rval;
1042  if( entities.empty() ) return MB_SUCCESS;
1043 
1044  const int dim = CN::Dimension( TYPE_FROM_HANDLE( entities.front() ) );
1045  if( dim < 1 || dim > 3 || !entities.all_of_dimension( dim ) ) return MB_TYPE_OUT_OF_RANGE;
1046 
1047  // are we skinning all entities
1048  size_t count = entities.size();
1049  int num_total;
1050  rval = thisMB->get_number_entities_by_dimension( this_set, dim, num_total );
1051  if( MB_SUCCESS != rval ) return rval;
1052  bool all = ( count == (size_t)num_total );
1053 
1054  // Create a bit tag for fast intersection with input entities range.
1055  // If we're skinning all the entities in the mesh, we really don't
1056  // need the tag. To save memory, just create it with a default value
1057  // of one and don't set it. That way MOAB will return 1 for all
1058  // entities.
1059  Tag tag;
1060  char bit = all ? 1 : 0;
1061  rval = thisMB->tag_get_handle( NULL, 1, MB_TYPE_BIT, tag, MB_TAG_CREAT, &bit );
1062  if( MB_SUCCESS != rval ) return rval;
1063 
1064  // tag all entities in input range
1065  if( !all )
1066  {
1067  std::vector< unsigned char > vect( count, 1 );
1068  rval = thisMB->tag_set_data( tag, entities, &vect[0] );
1069  if( MB_SUCCESS != rval )
1070  {
1071  thisMB->tag_delete( tag );
1072  return rval;
1073  }
1074  }
1075 
1076  switch( dim )
1077  {
1078  case 1:
1079  if( skin_verts )
1080  rval = find_skin_vertices_1D( tag, entities, *skin_verts );
1081  else if( skin_elems )
1082  rval = find_skin_vertices_1D( tag, entities, *skin_elems );
1083  else
1084  rval = MB_SUCCESS;
1085  break;
1086  case 2:
1087  rval = find_skin_vertices_2D( this_set, tag, entities, skin_verts, skin_elems, skin_rev_elems,
1088  create_skin_elems, corners_only );
1089  break;
1090  case 3:
1091  rval = find_skin_vertices_3D( this_set, tag, entities, skin_verts, skin_elems, skin_rev_elems,
1092  create_skin_elems, corners_only );
1093  break;
1094  default:
1095  rval = MB_TYPE_OUT_OF_RANGE;
1096  break;
1097  }
1098 
1099  thisMB->tag_delete( tag );
1100  return rval;
1101 }

References moab::Range::all_of_dimension(), moab::CN::Dimension(), moab::Range::empty(), ErrorCode, find_skin_vertices_1D(), find_skin_vertices_2D(), find_skin_vertices_3D(), moab::Range::front(), moab::Interface::get_number_entities_by_dimension(), MB_SUCCESS, MB_TAG_CREAT, MB_TYPE_BIT, MB_TYPE_OUT_OF_RANGE, moab::Range::size(), moab::Interface::tag_delete(), moab::Interface::tag_get_handle(), moab::Interface::tag_set_data(), thisMB, and moab::TYPE_FROM_HANDLE().

Referenced by find_skin().

◆ find_skin_vertices_1D()

ErrorCode moab::Skinner::find_skin_vertices_1D ( Tag  tag,
const Range edges,
Range skin_verts 
)
protected

Skin edges.

Return any vertices adjacent to exactly one of the input edges.

Definition at line 1103 of file Skinner.cpp.

1104 {
1105  // This rather simple algorithm is provided for completeness
1106  // (not sure how often one really wants the 'skin' of a chain
1107  // or tangle of edges.)
1108  //
1109  // A vertex is on the skin of the edges if it is contained in exactly
1110  // one of the edges *in the input range*.
1111  //
1112  // This function expects the caller to have tagged all edges in the
1113  // input range with a value of one for the passed bit tag, and all
1114  // other edges with a value of zero. This allows us to do a faster
1115  // intersection with the input range and the edges adjacent to a vertex.
1116 
1117  ErrorCode rval;
1118  Range::iterator hint = skin_verts.begin();
1119 
1120  // All input entities must be edges.
1121  if( !edges.all_of_dimension( 1 ) ) return MB_TYPE_OUT_OF_RANGE;
1122 
1123  // get all the vertices
1124  Range verts;
1125  rval = thisMB->get_connectivity( edges, verts, true );
1126  if( MB_SUCCESS != rval ) return rval;
1127 
1128  // Test how many edges each input vertex is adjacent to.
1129  std::vector< char > tag_vals;
1130  std::vector< EntityHandle > adj;
1131  int n;
1132  for( Range::const_iterator it = verts.begin(); it != verts.end(); ++it )
1133  {
1134  // get edges adjacent to vertex
1135  adj.clear();
1136  rval = thisMB->get_adjacencies( &*it, 1, 1, false, adj );
1137  if( MB_SUCCESS != rval ) return rval;
1138  if( adj.empty() ) continue;
1139 
1140  // Intersect adjacent edges with the input list of edges
1141  tag_vals.resize( adj.size() );
1142  rval = thisMB->tag_get_data( tag, &adj[0], adj.size(), &tag_vals[0] );
1143  if( MB_SUCCESS != rval ) return rval;
1144 #ifdef MOAB_OLD_STD_COUNT
1145  n = 0;
1146  std::count( tag_vals.begin(), tag_vals.end(), '\001' );
1147 #else
1148  n = std::count( tag_vals.begin(), tag_vals.end(), '\001' );
1149 #endif
1150  // If adjacent to only one input edge, then vertex is on skin
1151  if( n == 1 )
1152  {
1153  hint = skin_verts.insert( hint, *it );
1154  }
1155  }
1156 
1157  return MB_SUCCESS;
1158 }

References moab::Range::all_of_dimension(), moab::Range::begin(), moab::Range::end(), ErrorCode, moab::Interface::get_adjacencies(), moab::Interface::get_connectivity(), moab::Range::insert(), MB_SUCCESS, MB_TYPE_OUT_OF_RANGE, moab::Interface::tag_get_data(), and thisMB.

Referenced by find_skin_vertices().

◆ find_skin_vertices_2D()

ErrorCode moab::Skinner::find_skin_vertices_2D ( const EntityHandle  this_set,
Tag  tag,
const Range faces,
Range skin_verts = 0,
Range skin_edges = 0,
Range reverse_edges = 0,
bool  create_edges = false,
bool  corners_only = false 
)
protected

Skin faces.

For the set of face sides (logical edges), return vertices on such sides and/or edges equivalent to such sides.

Parameters
facesSet of toplogically 2D entities to skin.
skin_vertsIf non-NULL, skin vertices will be added to this container.
skin_edgesIf non-NULL, skin edges will be added to this container
reverse_edgesIf skin_edges is not NULL and this is not NULL, then any existing skin edges that are reversed with respect to the skin side will be placed in this range instead of skin_edges. Note: this argument is ignored if skin_edges is NULL.
create_edgesIf true, edges equivalent to face sides on the skin that don't already exist will be created. Note: this parameter is honored regardless of whether or not skin edges or vertices are returned.
corners_onlyIf true, only skin vertices that correspond to the corners of sides will be returned (i.e. no higher-order nodes.) This argument is ignored if skin_verts is NULL.

Definition at line 1573 of file Skinner.cpp.

1581 {
1582  // This function iterates over all the vertices contained in the
1583  // input face list. For each such vertex, it then iterates over
1584  // all of the sides of the face elements adjacent to the vertex.
1585  // If an adjacent side is the side of only one of the input
1586  // faces, then that side is on the skin.
1587  //
1588  // This algorithm will visit each skin vertex exactly once. It
1589  // will visit each skin side once for each vertex in the side.
1590  //
1591  // This function expects the caller to have created the passed bit
1592  // tag and set it to one only for the faces in the passed range. This
1593  // tag is used to do a fast intersection of the faces adjacent to a
1594  // vertex with the faces in the input range (discard any for which the
1595  // tag is not set to one.)
1596 
1597  ErrorCode rval;
1598  std::vector< EntityHandle >::iterator i, j;
1599  Range::iterator hint;
1600  if( skin_verts ) hint = skin_verts->begin();
1601  std::vector< EntityHandle > storage;
1602  const EntityHandle* conn;
1603  int len;
1604  bool find_edges = skin_edges || create_edges;
1605  bool printed_nonconformal_ho_warning = false;
1607 
1608  if( !faces.all_of_dimension( 2 ) ) return MB_TYPE_OUT_OF_RANGE;
1609 
1610  // get all the vertices
1611  Range verts;
1612  rval = thisMB->get_connectivity( faces, verts, true );
1613  if( MB_SUCCESS != rval ) return rval;
1614 
1615  std::vector< char > tag_vals;
1616  std::vector< EntityHandle > adj;
1617  AdjSides< 2 > adj_edges;
1618  for( Range::const_iterator it = verts.begin(); it != verts.end(); ++it )
1619  {
1620  bool higher_order = false;
1621 
1622  // get all adjacent faces
1623  adj.clear();
1624  rval = thisMB->get_adjacencies( &*it, 1, 2, false, adj );
1625  if( MB_SUCCESS != rval ) return rval;
1626  if( adj.empty() ) continue;
1627 
1628  // remove those not in the input list (intersect with input list)
1629  i = j = adj.begin();
1630  tag_vals.resize( adj.size() );
1631  rval = thisMB->tag_get_data( tag, &adj[0], adj.size(), &tag_vals[0] );
1632  if( MB_SUCCESS != rval ) return rval;
1633  // remove non-tagged entries
1634  i = j = adj.begin();
1635  for( ; i != adj.end(); ++i )
1636  if( tag_vals[i - adj.begin()] ) *( j++ ) = *i;
1637  adj.erase( j, adj.end() );
1638 
1639  // For each adjacent face, check the edges adjacent to the current vertex
1640  adj_edges.clear(); // other vertex for adjacent edges
1641  for( i = adj.begin(); i != adj.end(); ++i )
1642  {
1643  rval = thisMB->get_connectivity( *i, conn, len, false, &storage );
1644  if( MB_SUCCESS != rval ) return rval;
1645 
1646  // For a single face element adjacent to this vertex, there
1647  // will be exactly two sides (edges) adjacent to the vertex.
1648  // Find the other vertex for each of the two edges.
1649 
1650  EntityHandle prev, next; // vertices of two adjacent edge-sides
1651  const int idx = std::find( conn, conn + len, *it ) - conn;
1652  assert( idx != len );
1653 
1654  if( TYPE_FROM_HANDLE( *i ) == MBTRI && len > 3 )
1655  {
1656  len = 3;
1657  higher_order = true;
1658  if( idx > 2 )
1659  { // skip higher-order nodes for now
1660  if( !printed_nonconformal_ho_warning )
1661  {
1662  printed_nonconformal_ho_warning = true;
1663  std::cerr << "Non-conformal higher-order mesh detected in skinner: "
1664  << "vertex " << ID_FROM_HANDLE( *it ) << " is a corner in "
1665  << "some elements and a higher-order node in others" << std::endl;
1666  }
1667  continue;
1668  }
1669  }
1670  else if( TYPE_FROM_HANDLE( *i ) == MBQUAD && len > 4 )
1671  {
1672  len = 4;
1673  higher_order = true;
1674  if( idx > 3 )
1675  { // skip higher-order nodes for now
1676  if( !printed_nonconformal_ho_warning )
1677  {
1678  printed_nonconformal_ho_warning = true;
1679  std::cerr << "Non-conformal higher-order mesh detected in skinner: "
1680  << "vertex " << ID_FROM_HANDLE( *it ) << " is a corner in "
1681  << "some elements and a higher-order node in others" << std::endl;
1682  }
1683  continue;
1684  }
1685  }
1686 
1687  // so it must be a MBPOLYGON
1688  const int prev_idx = ( idx + len - 1 ) % len; // this should be fine, always, even for padded case
1689  prev = conn[prev_idx];
1690  next = conn[( idx + 1 ) % len];
1691  if( next == conn[idx] ) // it must be the padded case, so roll to the beginning
1692  next = conn[0];
1693 
1694  // Insert sides (edges) in our list of candidate skin sides
1695  adj_edges.insert( &prev, 1, *i, prev_idx );
1696  adj_edges.insert( &next, 1, *i, idx );
1697  }
1698 
1699  // If vertex is not on skin, advance to next vertex.
1700  // adj_edges handled checking for duplicates on insertion.
1701  // If every candidate skin edge occurred more than once (was
1702  // not in fact on the skin), then we're done with this vertex.
1703  if( 0 == adj_edges.num_skin() ) continue;
1704 
1705  // If user requested Range of *vertices* on the skin...
1706  if( skin_verts )
1707  {
1708  // Put skin vertex in output list
1709  hint = skin_verts->insert( hint, *it );
1710 
1711  // Add mid edge nodes to vertex list
1712  if( !corners_only && higher_order )
1713  {
1714  for( AdjSides< 2 >::const_iterator p = adj_edges.begin(); p != adj_edges.end(); ++p )
1715  {
1716  if( p->skin() )
1717  {
1718  face = p->adj_elem;
1719  EntityType type = TYPE_FROM_HANDLE( face );
1720 
1721  rval = thisMB->get_connectivity( face, conn, len, false );
1722  if( MB_SUCCESS != rval ) return rval;
1723  if( !CN::HasMidEdgeNodes( type, len ) ) continue;
1724 
1725  EntityHandle ec[2] = { *it, p->handles[0] };
1726  int side, sense, offset;
1727  CN::SideNumber( type, conn, ec, 2, 1, side, sense, offset );
1728  offset = CN::HONodeIndex( type, len, 1, side );
1729  assert( offset >= 0 && offset < len );
1730  skin_verts->insert( conn[offset] );
1731  }
1732  }
1733  }
1734  }
1735 
1736  // If user requested Range of *edges* on the skin...
1737  if( find_edges )
1738  {
1739  // Search list of existing adjacent edges for any that are on the skin
1740  adj.clear();
1741  rval = thisMB->get_adjacencies( &*it, 1, 1, false, adj );
1742  if( MB_SUCCESS != rval ) return rval;
1743  for( i = adj.begin(); i != adj.end(); ++i )
1744  {
1745  rval = thisMB->get_connectivity( *i, conn, len, true );
1746  if( MB_SUCCESS != rval ) return rval;
1747 
1748  // bool equality expression within find_and_unmark call
1749  // will be evaluate to the index of *it in the conn array.
1750  //
1751  // Note that the order of the terms in the if statement is important.
1752  // We want to unmark any existing skin edges even if we aren't
1753  // returning them. Otherwise we'll end up creating duplicates
1754  // if create_edges is true and skin_edges is not.
1755  if( adj_edges.find_and_unmark( conn, ( conn[1] == *it ), face ) && skin_edges )
1756  {
1757  if( reversed_edges && edge_reversed( face, conn ) )
1758  reversed_edges->insert( *i );
1759  else
1760  skin_edges->insert( *i );
1761  }
1762  }
1763  }
1764 
1765  // If the user requested that we create new edges for sides
1766  // on the skin for which there is no existing edge, and there
1767  // are still skin sides for which no corresponding edge was found...
1768  if( create_edges && adj_edges.num_skin() )
1769  {
1770  // Create any skin edges that don't exist
1771  for( AdjSides< 2 >::const_iterator p = adj_edges.begin(); p != adj_edges.end(); ++p )
1772  {
1773  if( p->skin() )
1774  {
1775  EntityHandle edge, ec[] = { *it, p->handles[0] };
1776  rval = create_side( this_set, p->adj_elem, MBEDGE, ec, edge );
1777  if( MB_SUCCESS != rval ) return rval;
1778  if( skin_edges ) skin_edges->insert( edge );
1779  }
1780  }
1781  }
1782 
1783  } // end for each vertex
1784 
1785  return MB_SUCCESS;
1786 }

References moab::Range::all_of_dimension(), moab::Range::begin(), moab::AdjSides< CORNERS >::begin(), moab::AdjSides< CORNERS >::clear(), moab::Range::end(), moab::AdjSides< CORNERS >::end(), ErrorCode, moab::AdjSides< CORNERS >::find_and_unmark(), moab::CN::HasMidEdgeNodes(), moab::CN::HONodeIndex(), moab::ID_FROM_HANDLE(), moab::AdjSides< CORNERS >::insert(), moab::Range::insert(), MB_SUCCESS, MB_TYPE_OUT_OF_RANGE, MBEDGE, MBQUAD, MBTRI, moab::AdjSides< CORNERS >::num_skin(), moab::CN::SideNumber(), and moab::TYPE_FROM_HANDLE().

Referenced by find_skin_vertices().

◆ find_skin_vertices_3D()

ErrorCode moab::Skinner::find_skin_vertices_3D ( const EntityHandle  this_set,
Tag  tag,
const Range entities,
Range skin_verts = 0,
Range skin_faces = 0,
Range reverse_faces = 0,
bool  create_faces = false,
bool  corners_only = false 
)
protected

Skin volume mesh.

For the set of element sides (logical faces), return vertices on such sides and/or faces equivalent to such sides.

Parameters
entitiesSet of toplogically 3D entities to skin.
skin_vertsIf non-NULL, skin vertices will be added to this container.
skin_facesIf non-NULL, skin faces will be added to this container
reverse_facesIf skin_faces is not NULL and this is not NULL, then any existing skin faces that are reversed with respect to the skin side will be placed in this range instead of skin_faces. Note: this argument is ignored if skin_faces is NULL.
create_facesIf true, face equivalent to sides on the skin that don't already exist will be created. Note: this parameter is honored regardless of whether or not skin faces or vertices are returned.
corners_onlyIf true, only skin vertices that correspond to the corners of sides will be returned (i.e. no higher-order nodes.) This argument is ignored if skin_verts is NULL.

Definition at line 1788 of file Skinner.cpp.

1796 {
1797  // This function iterates over all the vertices contained in the
1798  // input vol elem list. For each such vertex, it then iterates over
1799  // all of the sides of the vol elements adjacent to the vertex.
1800  // If an adjacent side is the side of only one of the input
1801  // elements, then that side is on the skin.
1802  //
1803  // This algorithm will visit each skin vertex exactly once. It
1804  // will visit each skin side once for each vertex in the side.
1805  //
1806  // This function expects the caller to have created the passed bit
1807  // tag and set it to one only for the elements in the passed range. This
1808  // tag is used to do a fast intersection of the elements adjacent to a
1809  // vertex with the elements in the input range (discard any for which the
1810  // tag is not set to one.)
1811  //
1812  // For each vertex, iterate over each adjacent element. Construct
1813  // lists of the sides of each adjacent element that contain the vertex.
1814  //
1815  // A list of three-vertex sides is kept for all triangular faces,
1816  // included three-vertex faces of type MBPOLYGON. Putting polygons
1817  // in the same list ensures that we find polyhedron and non-polyhedron
1818  // elements that are adjacent.
1819  //
1820  // A list of four-vertex sides is kept for all quadrilateral faces,
1821  // including four-vertex faces of type MBPOLYGON.
1822  //
1823  // Sides with more than four vertices must have an explicit MBPOLYGON
1824  // element representing them because MBPOLYHEDRON connectivity is a
1825  // list of faces rather than vertices. So the third list (vertices>=5),
1826  // need contain only the handle of the face rather than the vertex handles.
1827 
1828  ErrorCode rval;
1829  std::vector< EntityHandle >::iterator i, j;
1830  Range::iterator hint;
1831  if( skin_verts ) hint = skin_verts->begin();
1832  std::vector< EntityHandle > storage, storage2; // temp storage for conn lists
1833  const EntityHandle *conn, *conn2;
1834  int len, len2;
1835  bool find_faces = skin_faces || create_faces;
1836  int clen, side, sense, offset, indices[9];
1837  EntityType face_type;
1838  EntityHandle elem;
1839  bool printed_nonconformal_ho_warning = false;
1840 
1841  if( !entities.all_of_dimension( 3 ) ) return MB_TYPE_OUT_OF_RANGE;
1842 
1843  // get all the vertices
1844  Range verts;
1845  rval = thisMB->get_connectivity( entities, verts, true );
1846  if( MB_SUCCESS != rval ) return rval;
1847  // if there are polyhedra in the input list, need to make another
1848  // call to get vertices from faces
1849  if( !verts.all_of_dimension( 0 ) )
1850  {
1851  Range::iterator it = verts.upper_bound( MBVERTEX );
1852  Range pfaces;
1853  pfaces.merge( it, verts.end() );
1854  verts.erase( it, verts.end() );
1855  rval = thisMB->get_connectivity( pfaces, verts, true );
1856  if( MB_SUCCESS != rval ) return rval;
1857  assert( verts.all_of_dimension( 0 ) );
1858  }
1859 
1860  AdjSides< 4 > adj_quads; // 4-node sides adjacent to a vertex
1861  AdjSides< 3 > adj_tris; // 3-node sides adjacent to a vertex
1862  AdjSides< 2 > adj_poly; // n-node sides (n>5) adjacent to vertex
1863  // (must have an explicit polygon, so store
1864  // polygon handle rather than vertices.)
1865  std::vector< char > tag_vals;
1866  std::vector< EntityHandle > adj;
1867  for( Range::const_iterator it = verts.begin(); it != verts.end(); ++it )
1868  {
1869  bool higher_order = false;
1870 
1871  // get all adjacent elements
1872  adj.clear();
1873  rval = thisMB->get_adjacencies( &*it, 1, 3, false, adj );
1874  if( MB_SUCCESS != rval ) return rval;
1875  if( adj.empty() ) continue;
1876 
1877  // remove those not tagged (intersect with input range)
1878  i = j = adj.begin();
1879  tag_vals.resize( adj.size() );
1880  rval = thisMB->tag_get_data( tag, &adj[0], adj.size(), &tag_vals[0] );
1881  if( MB_SUCCESS != rval ) return rval;
1882  for( ; i != adj.end(); ++i )
1883  if( tag_vals[i - adj.begin()] ) *( j++ ) = *i;
1884  adj.erase( j, adj.end() );
1885 
1886  // Build lists of sides of 3D element adjacent to the current vertex
1887  adj_quads.clear(); // store three other vertices for each adjacent quad face
1888  adj_tris.clear(); // store two other vertices for each adjacent tri face
1889  adj_poly.clear(); // store handle of each adjacent polygonal face
1890  int idx;
1891  for( i = adj.begin(); i != adj.end(); ++i )
1892  {
1893  const EntityType type = TYPE_FROM_HANDLE( *i );
1894 
1895  // Special case for POLYHEDRA
1896  if( type == MBPOLYHEDRON )
1897  {
1898  rval = thisMB->get_connectivity( *i, conn, len );
1899  if( MB_SUCCESS != rval ) return rval;
1900  for( int k = 0; k < len; ++k )
1901  {
1902  rval = thisMB->get_connectivity( conn[k], conn2, len2, true, &storage2 );
1903  if( MB_SUCCESS != rval ) return rval;
1904  idx = std::find( conn2, conn2 + len2, *it ) - conn2;
1905  if( idx == len2 ) // vertex not in this face
1906  continue;
1907 
1908  // Treat 3- and 4-vertex faces specially, so that
1909  // if the mesh contains both elements and polyhedra,
1910  // we don't miss one type adjacent to the other.
1911  switch( len2 )
1912  {
1913  case 3:
1914  adj_tris.insert( conn2, idx, *i, k );
1915  break;
1916  case 4:
1917  adj_quads.insert( conn2, idx, *i, k );
1918  break;
1919  default:
1920  adj_poly.insert( conn + k, 1, *i, k );
1921  break;
1922  }
1923  }
1924  }
1925  else
1926  {
1927  rval = thisMB->get_connectivity( *i, conn, len, false, &storage );
1928  if( MB_SUCCESS != rval ) return rval;
1929 
1930  idx = std::find( conn, conn + len, *it ) - conn;
1931  assert( idx != len );
1932 
1933  if( len > CN::VerticesPerEntity( type ) )
1934  {
1935  higher_order = true;
1936  // skip higher-order nodes for now
1937  if( idx >= CN::VerticesPerEntity( type ) )
1938  {
1939  if( !printed_nonconformal_ho_warning )
1940  {
1941  printed_nonconformal_ho_warning = true;
1942  std::cerr << "Non-conformal higher-order mesh detected in skinner: "
1943  << "vertex " << ID_FROM_HANDLE( *it ) << " is a corner in "
1944  << "some elements and a higher-order node in others" << std::endl;
1945  }
1946  continue;
1947  }
1948  }
1949 
1950  // For each side of the element...
1951  const int num_faces = CN::NumSubEntities( type, 2 );
1952  for( int f = 0; f < num_faces; ++f )
1953  {
1954  int num_vtx;
1955  const short* face_indices = CN::SubEntityVertexIndices( type, 2, f, face_type, num_vtx );
1956  const short face_idx = std::find( face_indices, face_indices + num_vtx, (short)idx ) - face_indices;
1957  // skip sides that do not contain vertex from outer loop
1958  if( face_idx == num_vtx ) continue; // current vertex not in this face
1959 
1960  assert( num_vtx <= 4 ); // polyhedra handled above
1961  switch( face_type )
1962  {
1963  case MBTRI:
1964  adj_tris.insert( conn, face_idx, *i, f, face_indices );
1965  break;
1966  case MBQUAD:
1967  adj_quads.insert( conn, face_idx, *i, f, face_indices );
1968  break;
1969  default:
1970  return MB_TYPE_OUT_OF_RANGE;
1971  }
1972  }
1973  }
1974  } // end for (adj[3])
1975 
1976  // If vertex is not on skin, advance to next vertex
1977  if( 0 == ( adj_tris.num_skin() + adj_quads.num_skin() + adj_poly.num_skin() ) ) continue;
1978 
1979  // If user requested that skin *vertices* be passed back...
1980  if( skin_verts )
1981  {
1982  // Put skin vertex in output list
1983  hint = skin_verts->insert( hint, *it );
1984 
1985  // Add mid-edge and mid-face nodes to vertex list
1986  if( !corners_only && higher_order )
1987  {
1988  for( AdjSides< 3 >::const_iterator t = adj_tris.begin(); t != adj_tris.end(); ++t )
1989  {
1990  if( t->skin() )
1991  {
1992  elem = t->adj_elem;
1993  EntityType type = TYPE_FROM_HANDLE( elem );
1994 
1995  rval = thisMB->get_connectivity( elem, conn, len, false );
1996  if( MB_SUCCESS != rval ) return rval;
1997  if( !CN::HasMidNodes( type, len ) ) continue;
1998 
1999  EntityHandle ec[3] = { *it, t->handles[0], t->handles[1] };
2000  CN::SideNumber( type, conn, ec, 3, 2, side, sense, offset );
2001  CN::SubEntityNodeIndices( type, len, 2, side, face_type, clen, indices );
2002  assert( MBTRI == face_type );
2003  for( int k = 3; k < clen; ++k )
2004  skin_verts->insert( conn[indices[k]] );
2005  }
2006  }
2007  for( AdjSides< 4 >::const_iterator q = adj_quads.begin(); q != adj_quads.end(); ++q )
2008  {
2009  if( q->skin() )
2010  {
2011  elem = q->adj_elem;
2012  EntityType type = TYPE_FROM_HANDLE( elem );
2013 
2014  rval = thisMB->get_connectivity( elem, conn, len, false );
2015  if( MB_SUCCESS != rval ) return rval;
2016  if( !CN::HasMidNodes( type, len ) ) continue;
2017 
2018  EntityHandle ec[4] = { *it, q->handles[0], q->handles[1], q->handles[2] };
2019  CN::SideNumber( type, conn, ec, 4, 2, side, sense, offset );
2020  CN::SubEntityNodeIndices( type, len, 2, side, face_type, clen, indices );
2021  assert( MBQUAD == face_type );
2022  for( int k = 4; k < clen; ++k )
2023  skin_verts->insert( conn[indices[k]] );
2024  }
2025  }
2026  }
2027  }
2028 
2029  // If user requested that we pass back the list of 2D elements
2030  // representing the skin of the mesh...
2031  if( find_faces )
2032  {
2033  // Search list of adjacent faces for any that are on the skin
2034  adj.clear();
2035  rval = thisMB->get_adjacencies( &*it, 1, 2, false, adj );
2036  if( MB_SUCCESS != rval ) return rval;
2037 
2038  for( i = adj.begin(); i != adj.end(); ++i )
2039  {
2040  rval = thisMB->get_connectivity( *i, conn, len, true );
2041  if( MB_SUCCESS != rval ) return rval;
2042  const int idx2 = std::find( conn, conn + len, *it ) - conn;
2043  if( idx2 >= len )
2044  {
2045  assert( printed_nonconformal_ho_warning );
2046  continue;
2047  }
2048 
2049  // Note that the order of the terms in the if statements below
2050  // is important. We want to unmark any existing skin faces even
2051  // if we aren't returning them. Otherwise we'll end up creating
2052  // duplicates if create_faces is true.
2053  if( 3 == len )
2054  {
2055  if( adj_tris.find_and_unmark( conn, idx2, elem ) && skin_faces )
2056  {
2057  if( reversed_faces && face_reversed( elem, conn, MBTRI ) )
2058  reversed_faces->insert( *i );
2059  else
2060  skin_faces->insert( *i );
2061  }
2062  }
2063  else if( 4 == len )
2064  {
2065  if( adj_quads.find_and_unmark( conn, idx2, elem ) && skin_faces )
2066  {
2067  if( reversed_faces && face_reversed( elem, conn, MBQUAD ) )
2068  reversed_faces->insert( *i );
2069  else
2070  skin_faces->insert( *i );
2071  }
2072  }
2073  else
2074  {
2075  if( adj_poly.find_and_unmark( &*i, 1, elem ) && skin_faces ) skin_faces->insert( *i );
2076  }
2077  }
2078  }
2079 
2080  // If user does not want use to create new faces representing
2081  // sides for which there is currently no explicit element,
2082  // skip the remaining code and advance the outer loop to the
2083  // next vertex.
2084  if( !create_faces ) continue;
2085 
2086  // Polyhedra always have explicitly defined faces, so
2087  // there is no way we could need to create such a face.
2088  assert( 0 == adj_poly.num_skin() );
2089 
2090  // Create any skin tris that don't exist
2091  if( adj_tris.num_skin() )
2092  {
2093  for( AdjSides< 3 >::const_iterator t = adj_tris.begin(); t != adj_tris.end(); ++t )
2094  {
2095  if( t->skin() )
2096  {
2097  EntityHandle tri, c[3] = { *it, t->handles[0], t->handles[1] };
2098  rval = create_side( this_set, t->adj_elem, MBTRI, c, tri );
2099  if( MB_SUCCESS != rval ) return rval;
2100  if( skin_faces ) skin_faces->insert( tri );
2101  }
2102  }
2103  }
2104 
2105  // Create any skin quads that don't exist
2106  if( adj_quads.num_skin() )
2107  {
2108  for( AdjSides< 4 >::const_iterator q = adj_quads.begin(); q != adj_quads.end(); ++q )
2109  {
2110  if( q->skin() )
2111  {
2112  EntityHandle quad, c[4] = { *it, q->handles[0], q->handles[1], q->handles[2] };
2113  rval = create_side( this_set, q->adj_elem, MBQUAD, c, quad );
2114  if( MB_SUCCESS != rval ) return rval;
2115  if( skin_faces ) skin_faces->insert( quad );
2116  }
2117  }
2118  }
2119  } // end for each vertex
2120 
2121  return MB_SUCCESS;
2122 }

References moab::Range::all_of_dimension(), moab::Range::begin(), moab::AdjSides< CORNERS >::begin(), moab::AdjSides< CORNERS >::clear(), moab::Range::end(), moab::AdjSides< CORNERS >::end(), moab::Range::erase(), ErrorCode, moab::AdjSides< CORNERS >::find_and_unmark(), moab::CN::HasMidNodes(), moab::ID_FROM_HANDLE(), moab::AdjSides< CORNERS >::insert(), moab::Range::insert(), MB_SUCCESS, MB_TYPE_OUT_OF_RANGE, MBPOLYHEDRON, MBQUAD, MBTRI, MBVERTEX, moab::Range::merge(), moab::AdjSides< CORNERS >::num_skin(), moab::CN::NumSubEntities(), moab::CN::SideNumber(), moab::CN::SubEntityNodeIndices(), moab::CN::SubEntityVertexIndices(), moab::TYPE_FROM_HANDLE(), moab::Range::upper_bound(), and moab::CN::VerticesPerEntity().

Referenced by find_skin_vertices().

◆ has_larger_angle()

bool moab::Skinner::has_larger_angle ( EntityHandle entity1,
EntityHandle entity2,
double  reference_angle_cosine 
)
protected

Definition at line 984 of file Skinner.cpp.

985 {
986  // compare normals to get angle. We assume that the surface quads
987  // which we test here will be approximately planar
988 
989  double norm[2][3];
990  Util::normal( thisMB, entity1, norm[0][0], norm[0][1], norm[0][2] );
991  Util::normal( thisMB, entity2, norm[1][0], norm[1][1], norm[1][2] );
992 
993  double cosine = norm[0][0] * norm[1][0] + norm[0][1] * norm[1][1] + norm[0][2] * norm[1][2];
994 
995  if( cosine < reference_angle_cosine )
996  {
997  return true;
998  }
999 
1000  return false;
1001 }

References moab::Util::normal(), and thisMB.

Referenced by find_inferred_edges().

◆ initialize()

ErrorCode moab::Skinner::initialize ( )
protected

Definition at line 53 of file Skinner.cpp.

54 {
55  // go through and mark all the target dimension entities
56  // that already exist as not deleteable
57  // also get the connectivity tags for each type
58  // also populate adjacency information
59  EntityType type;
60  DimensionPair target_ent_types = CN::TypeDimensionMap[mTargetDim];
61 
62  void* null_ptr = NULL;
63 
64  ErrorCode result = thisMB->tag_get_handle( "skinner adj", sizeof( void* ), MB_TYPE_OPAQUE, mAdjTag,
65  MB_TAG_DENSE | MB_TAG_CREAT, &null_ptr );
66  MB_CHK_ERR( result );
67 
68  if( mDeletableMBTag == 0 )
69  {
70  result =
72  MB_CHK_ERR( result );
73  }
74 
75  Range entities;
76 
77  // go through each type at this dimension
78  for( type = target_ent_types.first; type <= target_ent_types.second; ++type )
79  {
80  // get the entities of this type in the MB
81  thisMB->get_entities_by_type( 0, type, entities );
82 
83  // go through each entity of this type in the MB
84  // and set its deletable tag to NO
85  Range::iterator iter, end_iter;
86  end_iter = entities.end();
87  for( iter = entities.begin(); iter != end_iter; ++iter )
88  {
89  unsigned char bit = 0x1;
90  result = thisMB->tag_set_data( mDeletableMBTag, &( *iter ), 1, &bit );
91  assert( MB_SUCCESS == result );
92  // add adjacency information too
93  if( TYPE_FROM_HANDLE( *iter ) != MBVERTEX ) add_adjacency( *iter );
94  }
95  }
96 
97  return MB_SUCCESS;
98 }

References add_adjacency(), moab::Range::begin(), moab::Range::end(), ErrorCode, moab::Interface::get_entities_by_type(), mAdjTag, MB_CHK_ERR, MB_SUCCESS, MB_TAG_BIT, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_BIT, MB_TYPE_OPAQUE, MBVERTEX, mDeletableMBTag, mTargetDim, moab::Interface::tag_get_handle(), moab::Interface::tag_set_data(), thisMB, moab::TYPE_FROM_HANDLE(), and moab::CN::TypeDimensionMap.

Referenced by classify_2d_boundary(), and find_skin_noadj().

◆ remove_adjacency()

ErrorCode moab::Skinner::remove_adjacency ( EntityHandle  entity)
protected

Definition at line 640 of file Skinner.cpp.

641 {
642  std::vector< EntityHandle > nodes, *adj = NULL;
643  ErrorCode result = thisMB->get_connectivity( &entity, 1, nodes );
644  MB_CHK_ERR( result );
645  std::vector< EntityHandle >::iterator iter = std::min_element( nodes.begin(), nodes.end() );
646 
647  if( iter == nodes.end() ) return MB_FAILURE;
648 
649  // remove this entity from the node
650  if( thisMB->tag_get_data( mAdjTag, &( *iter ), 1, &adj ) == MB_SUCCESS && adj != NULL )
651  {
652  iter = std::find( adj->begin(), adj->end(), entity );
653  if( iter != adj->end() ) adj->erase( iter );
654  }
655 
656  return result;
657 }

References ErrorCode, moab::Interface::get_connectivity(), mAdjTag, MB_CHK_ERR, MB_SUCCESS, moab::Interface::tag_get_data(), and thisMB.

Referenced by find_skin_noadj().

◆ skin_box()

ErrorCode moab::Skinner::skin_box ( ScdBox box,
bool  get_vertices,
Range output_handles,
bool  create_skin_elements 
)
protected

skin a structured box, taking advantage of structured information

Definition at line 304 of file Skinner.cpp.

305 {
306  HomCoord bmin = box->box_min(), bmax = box->box_max();
307 
308  // don't support 1d boxes
309  if( bmin.j() == bmax.j() && bmin.k() == bmax.k() ) return MB_FAILURE;
310 
311  int dim = ( bmin.k() == bmax.k() ? 1 : 2 );
312 
313  ErrorCode rval;
314  EntityHandle ent;
315 
316  // i=min
317  for( int k = bmin.k(); k < bmax.k(); k++ )
318  {
319  for( int j = bmin.j(); j < bmax.j(); j++ )
320  {
321  ent = 0;
322  rval = box->get_adj_edge_or_face( dim, bmin.i(), j, k, 0, ent, create_skin_elements );
323  if( MB_SUCCESS != rval ) return rval;
324  if( ent ) output_handles.insert( ent );
325  }
326  }
327  // i=max
328  for( int k = bmin.k(); k < bmax.k(); k++ )
329  {
330  for( int j = bmin.j(); j < bmax.j(); j++ )
331  {
332  ent = 0;
333  rval = box->get_adj_edge_or_face( dim, bmax.i(), j, k, 0, ent, create_skin_elements );
334  if( MB_SUCCESS != rval ) return rval;
335  if( ent ) output_handles.insert( ent );
336  }
337  }
338  // j=min
339  for( int k = bmin.k(); k < bmax.k(); k++ )
340  {
341  for( int i = bmin.i(); i < bmax.i(); i++ )
342  {
343  ent = 0;
344  rval = box->get_adj_edge_or_face( dim, i, bmin.j(), k, 1, ent, create_skin_elements );
345  if( MB_SUCCESS != rval ) return rval;
346  if( ent ) output_handles.insert( ent );
347  }
348  }
349  // j=max
350  for( int k = bmin.k(); k < bmax.k(); k++ )
351  {
352  for( int i = bmin.i(); i < bmax.i(); i++ )
353  {
354  ent = 0;
355  rval = box->get_adj_edge_or_face( dim, i, bmax.j(), k, 1, ent, create_skin_elements );
356  if( MB_SUCCESS != rval ) return rval;
357  if( ent ) output_handles.insert( ent );
358  }
359  }
360  // k=min
361  for( int j = bmin.j(); j < bmax.j(); j++ )
362  {
363  for( int i = bmin.i(); i < bmax.i(); i++ )
364  {
365  ent = 0;
366  rval = box->get_adj_edge_or_face( dim, i, j, bmin.k(), 2, ent, create_skin_elements );
367  if( MB_SUCCESS != rval ) return rval;
368  if( ent ) output_handles.insert( ent );
369  }
370  }
371  // k=max
372  for( int j = bmin.j(); j < bmax.j(); j++ )
373  {
374  for( int i = bmin.i(); i < bmax.i(); i++ )
375  {
376  ent = 0;
377  rval = box->get_adj_edge_or_face( dim, i, j, bmax.k(), 2, ent, create_skin_elements );
378  if( MB_SUCCESS != rval ) return rval;
379  if( ent ) output_handles.insert( ent );
380  }
381  }
382 
383  if( get_vertices )
384  {
385  Range verts;
386  rval = thisMB->get_adjacencies( output_handles, 0, true, verts, Interface::UNION );
387  if( MB_SUCCESS != rval ) return rval;
388  output_handles.merge( verts );
389  }
390 
391  return MB_SUCCESS;
392 }

References moab::ScdBox::box_max(), moab::ScdBox::box_min(), ErrorCode, moab::ScdBox::get_adj_edge_or_face(), moab::Interface::get_adjacencies(), moab::HomCoord::i(), moab::Range::insert(), moab::HomCoord::j(), moab::HomCoord::k(), MB_SUCCESS, moab::Range::merge(), thisMB, and moab::Interface::UNION.

Referenced by find_skin_scd().

Member Data Documentation

◆ mAdjTag

Tag moab::Skinner::mAdjTag
protected

Definition at line 50 of file Skinner.hpp.

Referenced by add_adjacency(), deinitialize(), find_match(), initialize(), and remove_adjacency().

◆ mDeletableMBTag

Tag moab::Skinner::mDeletableMBTag
protected

Definition at line 49 of file Skinner.hpp.

Referenced by deinitialize(), entity_deletable(), and initialize().

◆ mTargetDim

int moab::Skinner::mTargetDim
protected

Definition at line 51 of file Skinner.hpp.

Referenced by classify_2d_boundary(), find_skin_noadj(), and initialize().

◆ thisMB


The documentation for this class was generated from the following files: