MOAB: Mesh Oriented datABase  (version 5.4.1)
moab::SimplexTemplateRefiner Class Reference

#include <SimplexTemplateRefiner.hpp>

+ Inheritance diagram for moab::SimplexTemplateRefiner:
+ Collaboration diagram for moab::SimplexTemplateRefiner:

Public Member Functions

 SimplexTemplateRefiner ()
 Construct a template refiner.
virtual ~SimplexTemplateRefiner ()
 Empty destructor for good form.
virtual bool refine_entity (EntityType etyp, EntityHandle entity)
 Stream a single mesh entity through the refiner.
virtual unsigned long get_heap_size_bound (int max_recursions) const
 Bound on the number of new vertices used to allocate the heap.
virtual bool set_tag_assigner (SimplexTemplateTagAssigner *ta)
 Set the function object used to decide which tag values an edge or face midpoint is assigned.
SimplexTemplateTagAssignerget_tag_assigner () const
virtual bool prepare (RefinerTagManager *tmgr, EntityRefinerOutputFunctor *ofunc)
 Set the function object used to decide whether an edge is subdivided or not.

Protected Member Functions

void refine_0_simplex (const double *v0, const void *t0, EntityHandle h0)
 "Refine" a vertex by passing it through to the output.
bool refine_1_simplex (int max_depth, const double *v0, const void *t0, EntityHandle h0, const double *v1, const void *t1, EntityHandle h1)
 Refine an edge.
bool refine_2_simplex (int max_depth, int move, const double *v0, const void *t0, EntityHandle h0, const double *v1, const void *t1, EntityHandle h1, const double *v2, const void *t2, EntityHandle h2)
 Refine a triangle.
bool refine_3_simplex (int max_depth, double *v0, void *t0, EntityHandle h0, double *v1, void *t1, EntityHandle h1, double *v2, void *t2, EntityHandle h2, double *v3, void *t3, EntityHandle h3)
 Refine a tetrahedron.
int best_tets (int *alternates, double *[14], int, int)
void assign_parametric_coordinates (int num_nodes, const double *src, double *tgt)
 This is used by refine_entity to assign parametric coordinates to corners of each element.

Static Protected Member Functions

static bool compare_Hopf_cross_string_dist (const double *v00, const double *v01, const double *v10, const double *v11)
 Returns true if || a0a1 || < || b0b1 ||.

Protected Attributes

SimplexTemplateTagAssignertag_assigner
RefinerTagManagertag_manager
std::vector< double > corner_coords
std::vector< void * > corner_tags
std::vector< EntityHandlecorner_handles
bool input_is_output

Static Protected Attributes

static int template_index [64][2]
static int permutations_from_index [24][14]
static int templates []

Detailed Description

This is a concrete subclass of EntityRefiner that implements refinement using templates applied to simplices. Entities that are not simplices are divided into tetrahedra, triangles, or lines before being processed. Points are passed through unchanged.

Author:
David Thompson
Philippe Pebay
Date:
24 December 2007

Definition at line 42 of file SimplexTemplateRefiner.hpp.


Constructor & Destructor Documentation

Construct a template refiner.

Definition at line 29 of file SimplexTemplateRefiner.cpp.

References corner_coords, corner_handles, corner_tags, input_is_output, tag_assigner, and tag_manager.

{
    this->tag_manager  = 0;
    this->tag_assigner = new SimplexTemplateTagAssigner( this );
    this->corner_coords.resize( 6 * 8 );  // Hex has 8 verts w/ 6 coordinates each
    this->corner_tags.resize( 8 );        // Hex has 8 verts (this is a pointer, not the actual tag data)
    this->corner_handles.resize( 8 );     // Hex has 8 verts (this is a pointer, not actual hash data)
    this->input_is_output = false;        // Until we know better
}

Empty destructor for good form.

Definition at line 40 of file SimplexTemplateRefiner.cpp.

References tag_assigner.

{
    delete this->tag_assigner;
}

Member Function Documentation

void moab::SimplexTemplateRefiner::assign_parametric_coordinates ( int  num_nodes,
const double *  src,
double *  tgt 
) [protected]

This is used by refine_entity to assign parametric coordinates to corners of each element.

Definition at line 1639 of file SimplexTemplateRefiner.cpp.

Referenced by refine_entity().

{
    for( int i = 0; i < num_nodes; ++i, src += 3, tgt += 6 )
        for( int j = 0; j < 3; ++j )
            tgt[j] = src[j];
}
int moab::SimplexTemplateRefiner::best_tets ( int *  alternates,
double *  [14],
int  ,
int   
) [inline, protected]

Definition at line 107 of file SimplexTemplateRefiner.hpp.

Referenced by refine_3_simplex().

    {
        return alternates[0];
    }
bool moab::SimplexTemplateRefiner::compare_Hopf_cross_string_dist ( const double *  a0,
const double *  a1,
const double *  b0,
const double *  b1 
) [static, protected]

Returns true if || a0a1 || < || b0b1 ||.

We use this to test which triangulation has the best aspect ratio when there are 2 to choose from.

Definition at line 1651 of file SimplexTemplateRefiner.cpp.

Referenced by refine_2_simplex().

{
    double sq_mag_a = 0.;
    double sq_mag_b = 0.;
    for( int i = 0; i < 3; ++i )
    {
        double tmp;
        tmp = a0[i] - a1[i];
        sq_mag_a += tmp * tmp;
        tmp = b0[i] - b1[i];
        sq_mag_b += tmp * tmp;
    }
    return sq_mag_a < sq_mag_b;
}
unsigned long moab::SimplexTemplateRefiner::get_heap_size_bound ( int  max_recursions) const [inline, virtual]

Bound on the number of new vertices used to allocate the heap.

This bound is based on a hexahedron that is divided into 48 tetrahedra (a point is added to the center of each face so that compatible boundaries are guaranteed on neighboring hexahedra), each of which has 4 edges.

Implements moab::EntityRefiner.

Definition at line 49 of file SimplexTemplateRefiner.hpp.

    {
        return 48 * 4 * ( 1 << max_recursions ) + 8;
    }

Definition at line 55 of file SimplexTemplateRefiner.hpp.

References tag_assigner.

    {
        return this->tag_assigner;
    }

Set the function object used to decide whether an edge is subdivided or not.

Reimplemented from moab::EntityRefiner.

Definition at line 184 of file SimplexTemplateRefiner.cpp.

References moab::RefinerTagManager::get_input_mesh(), moab::RefinerTagManager::get_output_mesh(), input_is_output, moab::SimplexTemplateTagAssigner::set_tag_manager(), tag_assigner, and tag_manager.

{
    this->tag_manager = tmgr;
    this->tag_assigner->set_tag_manager( tmgr );
    this->input_is_output = ( this->tag_manager->get_input_mesh() == this->tag_manager->get_output_mesh() );
    // this->tag_assigner->set_edge_size_evaluator( this->edge_size_evaluator );
    return this->EntityRefiner::prepare( tmgr, ofunc );
}
void moab::SimplexTemplateRefiner::refine_0_simplex ( const double *  v0,
const void *  t0,
EntityHandle  h0 
) [protected]

"Refine" a vertex by passing it through to the output.

FIXME: There is some question as to whether this should pass vertices through since there does not appear to be a distinction between vertices as points in space and vertices as degrees-of-freedom in a mesh (i.e. a vertex that is treated as a lumped-parameter model).

Definition at line 208 of file SimplexTemplateRefiner.cpp.

References MBVERTEX, and moab::EntityRefiner::output_functor.

Referenced by refine_entity().

{
    // Ignore these arguments... the caller is responsible for calling the output functor to ensure
    // the vertex exists on the output.
    (void)v0;
    (void)t0;

    ( *this->output_functor )( h0 );
    ( *this->output_functor )( MBVERTEX );
}
bool moab::SimplexTemplateRefiner::refine_1_simplex ( int  max_depth,
const double *  v0,
const void *  t0,
EntityHandle  h0,
const double *  v1,
const void *  t1,
EntityHandle  h1 
) [protected]

Refine an edge.

Definition at line 221 of file SimplexTemplateRefiner.cpp.

References moab::EntityRefiner::edge_size_evaluator, moab::EdgeSizeEvaluator::evaluate_edge(), moab::EntityRefiner::heap_coord_storage(), moab::EntityRefiner::heap_tag_storage(), MBEDGE, moab::EntityRefiner::output_functor, and tag_assigner.

Referenced by refine_entity().

{
    int edge_code = 0;

    double* midptc;
    void* midptt;
    // NB: If support for multiple recursive subdivisions (without a merge in between) is required,
    //     this will have to change as it assumes that h0 and h1 have only a single entry.
    EntityHandle midpth = 0;

    if( max_depth-- > 0 )
    {
        midptc = this->heap_coord_storage();
        midptt = this->heap_tag_storage();
        int i;
        // make valgrind happy
        // vtkstd::fill( midpt0, midpt0 + 6, 0. );
        for( i = 0; i < 6; i++ )
            midptc[i] = ( v0[i] + v1[i] ) / 2.;

        ( *this->tag_assigner )( v0, t0, h0, midptc, midptt, v1, t1, h1 );
        if( this->edge_size_evaluator->evaluate_edge( v0, t0, midptc, midptt, v1, t1 ) )
        {
            edge_code = 1;
            midpth    = ( *this->output_functor )( h0, h1, midptc, midptt );
        }
    }

    switch( edge_code )
    {
            // No edges to subdivide
        case 0:
            ( *this->output_functor )( h0 );
            ( *this->output_functor )( h1 );
            ( *this->output_functor )( MBEDGE );
            break;

            // One edge to subdivide
        case 1:
            this->refine_1_simplex( max_depth, v0, t0, h0, midptc, midptt, midpth );
            this->refine_1_simplex( max_depth, midptc, midptt, midpth, v1, t1, h1 );
            break;
    }

    return ( 0 == edge_code ) ? false : true;
}
bool moab::SimplexTemplateRefiner::refine_2_simplex ( int  max_depth,
int  move,
const double *  v0,
const void *  t0,
EntityHandle  h0,
const double *  v1,
const void *  t1,
EntityHandle  h1,
const double *  v2,
const void *  t2,
EntityHandle  h2 
) [protected]

Refine a triangle.

Definition at line 276 of file SimplexTemplateRefiner.cpp.

References compare_Hopf_cross_string_dist(), moab::EntityRefiner::edge_size_evaluator, moab::EdgeSizeEvaluator::evaluate_edge(), moab::EntityRefiner::heap_coord_storage(), moab::EntityRefiner::heap_tag_storage(), MBTRI, moab::EntityRefiner::output_functor, and tag_assigner.

Referenced by refine_entity().

{
    int edge_code = 0;

    double* midpt0c;
    double* midpt1c;
    double* midpt2c;
    void* midpt0t;
    void* midpt1t;
    void* midpt2t;
    EntityHandle midpt0h = 0;
    EntityHandle midpt1h = 0;
    EntityHandle midpt2h = 0;

    if( max_depth-- > 0 )
    {
        int i;
        midpt0c = this->heap_coord_storage();
        midpt1c = this->heap_coord_storage();
        midpt2c = this->heap_coord_storage();
        midpt0t = this->heap_tag_storage();
        midpt1t = this->heap_tag_storage();
        midpt2t = this->heap_tag_storage();
        midpt0h = 0;
        midpt1h = 0;
        midpt2h = 0;
        for( i = 0; i < 6; ++i )
        {
            midpt0c[i] = ( v0[i] + v1[i] ) / 2.;
            midpt1c[i] = ( v1[i] + v2[i] ) / 2.;
            midpt2c[i] = ( v2[i] + v0[i] ) / 2.;
        }
        ( *this->tag_assigner )( v0, t0, h0, midpt0c, midpt0t, v1, t1, h1 );
        ( *this->tag_assigner )( v1, t1, h1, midpt1c, midpt1t, v2, t2, h2 );
        ( *this->tag_assigner )( v2, t2, h2, midpt2c, midpt2t, v0, t0, h0 );
        if( ( move & 1 ) && this->edge_size_evaluator->evaluate_edge( v0, t0, midpt0c, midpt0t, v1, t1 ) )
        {
            edge_code += 1;
            midpt0h = ( *this->output_functor )( h0, h1, midpt0c, midpt0t );
        }
        if( ( move & 2 ) && this->edge_size_evaluator->evaluate_edge( v1, t1, midpt1c, midpt1t, v2, t2 ) )
        {
            edge_code += 2;
            midpt1h = ( *this->output_functor )( h1, h2, midpt1c, midpt1t );
        }
        if( ( move & 4 ) && this->edge_size_evaluator->evaluate_edge( v2, t2, midpt2c, midpt2t, v0, t0 ) )
        {
            edge_code += 4;
            midpt2h = ( *this->output_functor )( h2, h0, midpt2c, midpt2t );
        }
    }

    switch( edge_code )
    {
            // No edges to subdivide
        case 0:
            ( *this->output_functor )( h0 );
            ( *this->output_functor )( h1 );
            ( *this->output_functor )( h2 );
            ( *this->output_functor )( MBTRI );
            break;

            // One edge to subdivide
        case 1:
            this->refine_2_simplex( max_depth, move | 2, v0, t0, h0, midpt0c, midpt0t, midpt0h, v2, t2, h2 );
            this->refine_2_simplex( max_depth, move | 4, midpt0c, midpt0t, midpt0h, v1, t1, h1, v2, t2, h2 );
            break;
        case 2:
            this->refine_2_simplex( max_depth, move | 4, v0, t0, h0, v1, t1, h1, midpt1c, midpt1t, midpt1h );
            this->refine_2_simplex( max_depth, move | 1, v0, t0, h0, midpt1c, midpt1t, midpt1h, v2, t2, h2 );
            break;
        case 4:
            this->refine_2_simplex( max_depth, move | 2, v0, t0, h0, v1, t1, h1, midpt2c, midpt2t, midpt2h );
            this->refine_2_simplex( max_depth, move | 1, midpt2c, midpt2t, midpt2h, v1, t1, h1, v2, t2, h2 );
            break;

            // Two edges to subdivide
        case 3:
            this->refine_2_simplex( max_depth, move | 4, midpt0c, midpt0t, midpt0h, v1, t1, h1, midpt1c, midpt1t,
                                    midpt1h );
            if( this->compare_Hopf_cross_string_dist( v2, midpt0c, v0, midpt1c ) )
            {
                this->refine_2_simplex( max_depth, move | 5, midpt0c, midpt0t, midpt0h, midpt1c, midpt1t, midpt1h, v2,
                                        t2, h2 );
                this->refine_2_simplex( max_depth, move | 2, v0, t0, h0, midpt0c, midpt0t, midpt0h, v2, t2, h2 );
            }
            else
            {
                this->refine_2_simplex( max_depth, move | 6, v0, t0, h0, midpt0c, midpt0t, midpt0h, midpt1c, midpt1t,
                                        midpt1h );
                this->refine_2_simplex( max_depth, move | 1, v0, t0, h0, midpt1c, midpt1t, midpt1h, v2, t2, h2 );
            }
            break;
        case 5:
            this->refine_2_simplex( max_depth, move | 2, v0, t0, h0, midpt0c, midpt0t, midpt0h, midpt2c, midpt2t,
                                    midpt2h );
            if( this->compare_Hopf_cross_string_dist( v2, midpt0c, v1, midpt2c ) )
            {
                this->refine_2_simplex( max_depth, move | 4, midpt0c, midpt0t, midpt0h, v1, t1, h1, v2, t2, h2 );
                this->refine_2_simplex( max_depth, move | 3, midpt2c, midpt2t, midpt2h, midpt0c, midpt0t, midpt0h, v2,
                                        t2, h2 );
            }
            else
            {
                this->refine_2_simplex( max_depth, move | 6, midpt0c, midpt0t, midpt0h, v1, t1, h1, midpt2c, midpt2t,
                                        midpt2h );
                this->refine_2_simplex( max_depth, move | 1, midpt2c, midpt2t, midpt2h, v1, t1, h1, v2, t2, h2 );
            }
            break;
        case 6:
            this->refine_2_simplex( max_depth, move | 1, midpt2c, midpt2t, midpt2h, midpt1c, midpt1t, midpt1h, v2, t2,
                                    h2 );
            if( this->compare_Hopf_cross_string_dist( v0, midpt1c, v1, midpt2c ) )
            {
                this->refine_2_simplex( max_depth, move | 3, v0, t0, h0, midpt1c, midpt1t, midpt1h, midpt2c, midpt2t,
                                        midpt2h );
                this->refine_2_simplex( max_depth, move | 4, v0, t0, h0, v1, t1, h1, midpt1c, midpt1t, midpt1h );
            }
            else
            {
                this->refine_2_simplex( max_depth, move | 2, v0, t0, h0, v1, t1, h1, midpt2c, midpt2t, midpt2h );
                this->refine_2_simplex( max_depth, move | 5, midpt2c, midpt2t, midpt2h, v1, t1, h1, midpt1c, midpt1t,
                                        midpt1h );
            }
            break;

            // Three edges to subdivide
        case 7:
            this->refine_2_simplex( max_depth, 7, midpt0c, midpt0t, midpt0h, midpt1c, midpt1t, midpt1h, midpt2c,
                                    midpt2t, midpt2h );
            this->refine_2_simplex( max_depth, move | 2, v0, t0, h0, midpt0c, midpt0t, midpt0h, midpt2c, midpt2t,
                                    midpt2h );
            this->refine_2_simplex( max_depth, move | 4, midpt0c, midpt0t, midpt0h, v1, t1, h1, midpt1c, midpt1t,
                                    midpt1h );
            this->refine_2_simplex( max_depth, move | 1, midpt2c, midpt2t, midpt2h, midpt1c, midpt1t, midpt1h, v2, t2,
                                    h2 );
            break;
    }

    return true;
}
bool moab::SimplexTemplateRefiner::refine_3_simplex ( int  max_depth,
double *  v0,
void *  t0,
EntityHandle  h0,
double *  v1,
void *  t1,
EntityHandle  h1,
double *  v2,
void *  t2,
EntityHandle  h2,
double *  v3,
void *  t3,
EntityHandle  h3 
) [protected]

Refine a tetrahedron.

Definition at line 430 of file SimplexTemplateRefiner.cpp.

References best_tets(), moab::EntityRefiner::edge_size_evaluator, moab::EdgeSizeEvaluator::evaluate_edge(), h1, moab::EntityRefiner::heap_coord_storage(), moab::EntityRefiner::heap_tag_storage(), MB_TESSELLATOR_INCR_CASE_COUNT, MB_TESSELLATOR_INCR_SUBCASE_COUNT, MBTET, moab::EntityRefiner::output_functor, P, permutations_from_index, t, tag_assigner, template_index, templates, and vertex_coords().

Referenced by refine_entity().

{
    int edge_code = 0;

    double* midpt0c;
    double* midpt1c;
    double* midpt2c;
    double* midpt3c;
    double* midpt4c;
    double* midpt5c;

    void* midpt0t;
    void* midpt1t;
    void* midpt2t;
    void* midpt3t;
    void* midpt4t;
    void* midpt5t;

    EntityHandle midpt0h = 0;
    EntityHandle midpt1h = 0;
    EntityHandle midpt2h = 0;
    EntityHandle midpt3h = 0;
    EntityHandle midpt4h = 0;
    EntityHandle midpt5h = 0;

    if( max_depth-- > 0 )
    {
        midpt0c = this->heap_coord_storage();
        midpt1c = this->heap_coord_storage();
        midpt2c = this->heap_coord_storage();
        midpt3c = this->heap_coord_storage();
        midpt4c = this->heap_coord_storage();
        midpt5c = this->heap_coord_storage();

        midpt0t = this->heap_tag_storage();
        midpt1t = this->heap_tag_storage();
        midpt2t = this->heap_tag_storage();
        midpt3t = this->heap_tag_storage();
        midpt4t = this->heap_tag_storage();
        midpt5t = this->heap_tag_storage();

        for( int i = 0; i < 6; ++i )
        {
            midpt0c[i] = ( v0[i] + v1[i] ) * .5;
            midpt1c[i] = ( v1[i] + v2[i] ) * .5;
            midpt2c[i] = ( v2[i] + v0[i] ) * .5;
            midpt3c[i] = ( v0[i] + v3[i] ) * .5;
            midpt4c[i] = ( v1[i] + v3[i] ) * .5;
            midpt5c[i] = ( v2[i] + v3[i] ) * .5;
        }

        ( *this->tag_assigner )( v0, t0, h0, midpt0c, midpt0t, v1, t1, h1 );
        ( *this->tag_assigner )( v1, t1, h1, midpt1c, midpt1t, v2, t2, h2 );
        ( *this->tag_assigner )( v2, t2, h2, midpt2c, midpt2t, v0, t0, h0 );
        ( *this->tag_assigner )( v0, t0, h0, midpt3c, midpt3t, v3, t3, h3 );
        ( *this->tag_assigner )( v1, t1, h1, midpt4c, midpt4t, v3, t3, h3 );
        ( *this->tag_assigner )( v2, t2, h2, midpt5c, midpt5t, v3, t3, h3 );

        if( this->edge_size_evaluator->evaluate_edge( v0, t0, midpt0c, midpt0t, v1, t1 ) )
        {
            edge_code |= 1;
            midpt0h = ( *this->output_functor )( h0, h1, midpt0c, midpt0t );
        }
        if( this->edge_size_evaluator->evaluate_edge( v1, t1, midpt1c, midpt1t, v2, t2 ) )
        {
            edge_code |= 2;
            midpt1h = ( *this->output_functor )( h1, h2, midpt1c, midpt1t );
        }
        if( this->edge_size_evaluator->evaluate_edge( v2, t2, midpt2c, midpt2t, v0, t0 ) )
        {
            edge_code |= 4;
            midpt2h = ( *this->output_functor )( h2, h0, midpt2c, midpt2t );
        }
        if( this->edge_size_evaluator->evaluate_edge( v0, t0, midpt3c, midpt3t, v3, t3 ) )
        {
            edge_code |= 8;
            midpt3h = ( *this->output_functor )( h0, h3, midpt3c, midpt3t );
        }
        if( this->edge_size_evaluator->evaluate_edge( v1, t1, midpt4c, midpt4t, v3, t3 ) )
        {
            edge_code |= 16;
            midpt4h = ( *this->output_functor )( h1, h3, midpt4c, midpt4t );
        }
        if( this->edge_size_evaluator->evaluate_edge( v2, t2, midpt5c, midpt5t, v3, t3 ) )
        {
            edge_code |= 32;
            midpt5h = ( *this->output_functor )( h2, h3, midpt5c, midpt5t );
        }
    }

    double edge_length2[6];
    for( int ei = 0; ei < 6; ++ei )
        edge_length2[ei] = 0.;

    for( int c = 0; c < 3; ++c )
    {
        double tmp;
        tmp = v1[c] - v0[c];
        edge_length2[0] += tmp * tmp;
        tmp = v2[c] - v1[c];
        edge_length2[1] += tmp * tmp;
        tmp = v2[c] - v0[c];
        edge_length2[2] += tmp * tmp;
        tmp = v3[c] - v0[c];
        edge_length2[3] += tmp * tmp;
        tmp = v3[c] - v1[c];
        edge_length2[4] += tmp * tmp;
        tmp = v3[c] - v2[c];
        edge_length2[5] += tmp * tmp;
    }

    if( 0 == edge_code )
    {
        // No edges to subdivide
        ( *this->output_functor )( h0 );
        ( *this->output_functor )( h1 );
        ( *this->output_functor )( h2 );
        ( *this->output_functor )( h3 );
        ( *this->output_functor )( MBTET );

        return false;
    }

    double* facept0c;
    double* facept1c;
    double* facept2c;
    double* facept3c;
    facept0c                  = this->heap_coord_storage();
    facept1c                  = this->heap_coord_storage();
    facept2c                  = this->heap_coord_storage();
    facept3c                  = this->heap_coord_storage();
    double* vertex_coords[14] = { v0,      v1,      v2,      v3,       midpt0c,  midpt1c,  midpt2c,
                                  midpt3c, midpt4c, midpt5c, facept0c, facept1c, facept2c, facept3c };

    void* facept0t        = this->heap_tag_storage();
    void* facept1t        = this->heap_tag_storage();
    void* facept2t        = this->heap_tag_storage();
    void* facept3t        = this->heap_tag_storage();
    void* vertex_tags[14] = { t0,      t1,      t2,      t3,       midpt0t,  midpt1t,  midpt2t,
                              midpt3t, midpt4t, midpt5t, facept0t, facept1t, facept2t, facept3t };

    EntityHandle vertex_hash[14] = { h0, h1, h2, h3, midpt0h, midpt1h, midpt2h, midpt3h, midpt4h, midpt5h, 0, 0, 0, 0 };

    // Generate tetrahedra that are compatible except when edge
    // lengths are equal on indeterminately subdivided faces.
    double* permuted_coords[14];
    void* permuted_tags[14];
    EntityHandle permuted_hash[14];
    double permlen[6];  // permuted edge lengths
    int C = SimplexTemplateRefiner::template_index[edge_code][0];
    int P = SimplexTemplateRefiner::template_index[edge_code][1];

    // 1. Permute the tetrahedron into our canonical configuration
    for( int i = 0; i < 14; ++i )
    {
        permuted_coords[i] = vertex_coords[SimplexTemplateRefiner::permutations_from_index[P][i]];
        permuted_tags[i]   = vertex_tags[SimplexTemplateRefiner::permutations_from_index[P][i]];
        permuted_hash[i]   = vertex_hash[SimplexTemplateRefiner::permutations_from_index[P][i]];
    }

    for( int i = 4; i < 10; ++i )
    {
        // permute edge lengths too
        permlen[i - 4] = edge_length2[SimplexTemplateRefiner::permutations_from_index[P][i] - 4];
    }

    int comparison_bits;
    std::stack< int* > output_tets;
    std::stack< int* > output_perm;
    std::stack< int > output_sign;

    // cout << "Case " << C << "  Permutation " << P << endl;
    // 2. Generate tetrahedra based on the configuration.
    //    Note that case 0 is handled above (edgeCode == 0).

    switch( C )
    {
        case 1:  // Ruprecht-Müller Case 1
            MB_TESSELLATOR_INCR_CASE_COUNT( 0 );
            output_tets.push( SimplexTemplateRefiner::templates + 0 );
            output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
            output_sign.push( 1 );
            MB_TESSELLATOR_INCR_SUBCASE_COUNT( 0, 0 );
            break;
        case 2:  // Ruprecht-Müller Case 2a
            comparison_bits = ( permlen[0] <= permlen[1] ? 1 : 0 ) | ( permlen[0] >= permlen[1] ? 2 : 0 ) | 0;
            if( ( comparison_bits & 3 ) == 3 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[10][i] =
                        ( permuted_coords[0][i] + permuted_coords[2][i] ) * .375 + permuted_coords[1][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[0], permuted_tags[2], permuted_tags[1], permuted_tags[10] );
                permuted_hash[10] = ( *this->output_functor )( permuted_hash[0], permuted_hash[2], permuted_hash[1],
                                                               permuted_coords[10], permuted_tags[10] );
            }
            MB_TESSELLATOR_INCR_CASE_COUNT( 1 );
            output_tets.push( SimplexTemplateRefiner::templates + 9 );
            output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
            output_sign.push( 1 );
            MB_TESSELLATOR_INCR_SUBCASE_COUNT( 1, 0 );
            switch( comparison_bits )
            {
                case 2:  // 0>1
                    output_tets.push( SimplexTemplateRefiner::templates + 14 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 1, 1 );
                    break;
                case 1:  // 1>0
                    output_tets.push( SimplexTemplateRefiner::templates + 14 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[13] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 1, 2 );
                    break;
                case 3:  // 0=1
                    output_tets.push( SimplexTemplateRefiner::templates + 23 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 1, 3 );
                    break;
            }
            break;
        case 3:  // Ruprecht-Müller Case 2b
            MB_TESSELLATOR_INCR_CASE_COUNT( 2 );
            output_tets.push( SimplexTemplateRefiner::templates + 40 );
            output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
            output_sign.push( 1 );
            MB_TESSELLATOR_INCR_SUBCASE_COUNT( 2, 0 );
            break;
        case 4:  // Ruprecht-Müller Case 3a
            comparison_bits = ( permlen[0] <= permlen[3] ? 1 : 0 ) | ( permlen[0] >= permlen[3] ? 2 : 0 ) |
                              ( permlen[2] <= permlen[3] ? 4 : 0 ) | ( permlen[2] >= permlen[3] ? 8 : 0 ) |
                              ( permlen[0] <= permlen[2] ? 16 : 0 ) | ( permlen[0] >= permlen[2] ? 32 : 0 ) | 0;
            if( ( comparison_bits & 3 ) == 3 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[11][i] =
                        ( permuted_coords[1][i] + permuted_coords[3][i] ) * .375 + permuted_coords[0][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[1], permuted_tags[3], permuted_tags[0], permuted_tags[11] );
                permuted_hash[11] = ( *this->output_functor )( permuted_hash[1], permuted_hash[3], permuted_hash[0],
                                                               permuted_coords[11], permuted_tags[11] );
            }
            if( ( comparison_bits & 12 ) == 12 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[13][i] =
                        ( permuted_coords[2][i] + permuted_coords[3][i] ) * .375 + permuted_coords[0][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[2], permuted_tags[3], permuted_tags[0], permuted_tags[13] );
                permuted_hash[13] = ( *this->output_functor )( permuted_hash[2], permuted_hash[3], permuted_hash[0],
                                                               permuted_coords[13], permuted_tags[13] );
            }
            if( ( comparison_bits & 48 ) == 48 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[10][i] =
                        ( permuted_coords[1][i] + permuted_coords[2][i] ) * .375 + permuted_coords[0][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[1], permuted_tags[2], permuted_tags[0], permuted_tags[10] );
                permuted_hash[10] = ( *this->output_functor )( permuted_hash[1], permuted_hash[2], permuted_hash[0],
                                                               permuted_coords[10], permuted_tags[10] );
            }
            MB_TESSELLATOR_INCR_CASE_COUNT( 3 );
            output_tets.push( SimplexTemplateRefiner::templates + 57 );
            output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
            output_sign.push( 1 );
            MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 0 );
            switch( comparison_bits )
            {
                case 42:  // 0>2>3<0
                    output_tets.push( SimplexTemplateRefiner::templates + 62 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 1 );
                    break;
                case 25:  // 2>3>0<2
                    output_tets.push( SimplexTemplateRefiner::templates + 62 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[11] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 2 );
                    break;
                case 37:  // 3>0>2<3
                    output_tets.push( SimplexTemplateRefiner::templates + 62 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[3] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 3 );
                    break;
                case 21:  // 3>2>0<3
                    output_tets.push( SimplexTemplateRefiner::templates + 62 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[22] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 4 );
                    break;
                case 26:  // 2>0>3<2
                    output_tets.push( SimplexTemplateRefiner::templates + 62 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[12] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 5 );
                    break;
                case 38:  // 0>3>2<0
                    output_tets.push( SimplexTemplateRefiner::templates + 62 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 6 );
                    break;
                case 58:  // 0=2>3<0
                    output_tets.push( SimplexTemplateRefiner::templates + 75 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 7 );
                    break;
                case 29:  // 2=3>0<2
                    output_tets.push( SimplexTemplateRefiner::templates + 75 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[11] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 8 );
                    break;
                case 39:  // 0=3>2<0
                    output_tets.push( SimplexTemplateRefiner::templates + 75 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[3] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 9 );
                    break;
                case 53:  // 3>0=2<3
                    output_tets.push( SimplexTemplateRefiner::templates + 96 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 10 );
                    break;
                case 46:  // 0>2=3<0
                    output_tets.push( SimplexTemplateRefiner::templates + 96 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[11] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 11 );
                    break;
                case 27:  // 2>0=3<2
                    output_tets.push( SimplexTemplateRefiner::templates + 96 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[3] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 12 );
                    break;
                case 63:  // 0=2=3=0
                    output_tets.push( SimplexTemplateRefiner::templates + 117 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 3, 13 );
                    break;
            }
            break;
        case 5:  // Ruprecht-Müller Case 3b
            MB_TESSELLATOR_INCR_CASE_COUNT( 4 );
            output_tets.push( SimplexTemplateRefiner::templates + 162 );
            output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
            output_sign.push( 1 );
            MB_TESSELLATOR_INCR_SUBCASE_COUNT( 4, 0 );
            break;
        case 6:  // Ruprecht-Müller Case 3c
            comparison_bits = ( permlen[0] <= permlen[1] ? 1 : 0 ) | ( permlen[0] >= permlen[1] ? 2 : 0 ) |
                              ( permlen[0] <= permlen[3] ? 4 : 0 ) | ( permlen[0] >= permlen[3] ? 8 : 0 ) | 0;
            if( ( comparison_bits & 3 ) == 3 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[10][i] =
                        ( permuted_coords[0][i] + permuted_coords[2][i] ) * .375 + permuted_coords[1][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[0], permuted_tags[2], permuted_tags[1], permuted_tags[10] );
                permuted_hash[10] = ( *this->output_functor )( permuted_hash[0], permuted_hash[2], permuted_hash[1],
                                                               permuted_coords[10], permuted_tags[10] );
            }
            if( ( comparison_bits & 12 ) == 12 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[11][i] =
                        ( permuted_coords[1][i] + permuted_coords[3][i] ) * .375 + permuted_coords[0][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[1], permuted_tags[3], permuted_tags[0], permuted_tags[11] );
                permuted_hash[11] = ( *this->output_functor )( permuted_hash[1], permuted_hash[3], permuted_hash[0],
                                                               permuted_coords[11], permuted_tags[11] );
            }
            MB_TESSELLATOR_INCR_CASE_COUNT( 5 );
            switch( comparison_bits )
            {
                case 10:  // 0>1,0>3
                    output_tets.push( SimplexTemplateRefiner::templates + 179 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 5, 0 );
                    break;
                case 5:  // 1>0,3>0
                    output_tets.push( SimplexTemplateRefiner::templates + 200 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 5, 1 );
                    break;
                case 6:  // 0>1,3>0
                    output_tets.push( SimplexTemplateRefiner::templates + 221 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 5, 2 );
                    break;
                case 9:  // 1>0,0>3
                    output_tets.push( SimplexTemplateRefiner::templates + 242 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 5, 3 );
                    break;
                case 11:  // 0=1,0>3
                    output_tets.push( SimplexTemplateRefiner::templates + 263 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 5, 4 );
                    break;
                case 14:  // 0=3,0>1
                    output_tets.push( SimplexTemplateRefiner::templates + 263 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 5, 5 );
                    break;
                case 7:  // 3>0,0=1
                    output_tets.push( SimplexTemplateRefiner::templates + 292 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 5, 6 );
                    break;
                case 13:  // 1>0,0=3
                    output_tets.push( SimplexTemplateRefiner::templates + 292 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 5, 7 );
                    break;
                case 15:  // 0=1,0=3
                    output_tets.push( SimplexTemplateRefiner::templates + 321 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 5, 8 );
                    break;
            }
            break;
        case 7:  // Ruprecht-Müller Case 3d
            comparison_bits = ( permlen[0] <= permlen[2] ? 1 : 0 ) | ( permlen[0] >= permlen[2] ? 2 : 0 ) |
                              ( permlen[0] <= permlen[4] ? 4 : 0 ) | ( permlen[0] >= permlen[4] ? 8 : 0 ) | 0;
            if( ( comparison_bits & 3 ) == 3 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[10][i] =
                        ( permuted_coords[1][i] + permuted_coords[2][i] ) * .375 + permuted_coords[0][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[1], permuted_tags[2], permuted_tags[0], permuted_tags[10] );
                permuted_hash[10] = ( *this->output_functor )( permuted_hash[1], permuted_hash[2], permuted_hash[0],
                                                               permuted_coords[10], permuted_tags[10] );
            }
            if( ( comparison_bits & 12 ) == 12 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[11][i] =
                        ( permuted_coords[0][i] + permuted_coords[3][i] ) * .375 + permuted_coords[1][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[0], permuted_tags[3], permuted_tags[1], permuted_tags[11] );
                permuted_hash[11] = ( *this->output_functor )( permuted_hash[0], permuted_hash[3], permuted_hash[1],
                                                               permuted_coords[11], permuted_tags[11] );
            }
            MB_TESSELLATOR_INCR_CASE_COUNT( 6 );
            switch( comparison_bits )
            {
                case 10:  // 0>4,0>2
                    output_tets.push( SimplexTemplateRefiner::templates + 362 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 6, 0 );
                    break;
                case 5:  // 4>0,2>0
                    output_tets.push( SimplexTemplateRefiner::templates + 383 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 6, 1 );
                    break;
                case 9:  // 0>4,2>0
                    output_tets.push( SimplexTemplateRefiner::templates + 404 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 6, 2 );
                    break;
                case 6:  // 4>0,0>2
                    output_tets.push( SimplexTemplateRefiner::templates + 425 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 6, 3 );
                    break;
                case 14:  // 0=4,0>2
                    output_tets.push( SimplexTemplateRefiner::templates + 446 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 6, 4 );
                    break;
                case 11:  // 0=2,0>4
                    output_tets.push( SimplexTemplateRefiner::templates + 446 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 6, 5 );
                    break;
                case 13:  // 2>0,0=4
                    output_tets.push( SimplexTemplateRefiner::templates + 475 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 6, 6 );
                    break;
                case 7:  // 4>0,0=2
                    output_tets.push( SimplexTemplateRefiner::templates + 475 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 6, 7 );
                    break;
                case 15:  // 0=4,0=2
                    output_tets.push( SimplexTemplateRefiner::templates + 504 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 6, 8 );
                    break;
            }
            break;
        case 8:  // Ruprecht-Müller Case 4a
            comparison_bits = ( permlen[4] <= permlen[5] ? 1 : 0 ) | ( permlen[4] >= permlen[5] ? 2 : 0 ) |
                              ( permlen[3] <= permlen[4] ? 4 : 0 ) | ( permlen[3] >= permlen[4] ? 8 : 0 ) | 0;
            if( ( comparison_bits & 3 ) == 3 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[12][i] =
                        ( permuted_coords[1][i] + permuted_coords[2][i] ) * .375 + permuted_coords[3][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[1], permuted_tags[2], permuted_tags[3], permuted_tags[12] );
                permuted_hash[12] = ( *this->output_functor )( permuted_hash[1], permuted_hash[2], permuted_hash[3],
                                                               permuted_coords[12], permuted_tags[12] );
            }
            if( ( comparison_bits & 12 ) == 12 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[11][i] =
                        ( permuted_coords[0][i] + permuted_coords[1][i] ) * .375 + permuted_coords[3][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[0], permuted_tags[1], permuted_tags[3], permuted_tags[11] );
                permuted_hash[11] = ( *this->output_functor )( permuted_hash[0], permuted_hash[1], permuted_hash[3],
                                                               permuted_coords[11], permuted_tags[11] );
            }
            MB_TESSELLATOR_INCR_CASE_COUNT( 7 );
            output_tets.push( SimplexTemplateRefiner::templates + 545 );
            output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
            output_sign.push( 1 );
            MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 0 );
            switch( comparison_bits )
            {
                case 5:  // 5>4>3
                    output_tets.push( SimplexTemplateRefiner::templates + 554 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 1 );
                    break;
                case 10:  // 3>4>5
                    output_tets.push( SimplexTemplateRefiner::templates + 554 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[13] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 2 );
                    break;
                case 6:  // 3<4>5
                    output_tets.push( SimplexTemplateRefiner::templates + 571 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 3 );
                    break;
                case 9:  // 3>4<5
                    output_tets.push( SimplexTemplateRefiner::templates + 588 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 4 );
                    break;
                case 14:  // 3=4>5
                    output_tets.push( SimplexTemplateRefiner::templates + 605 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 5 );
                    break;
                case 7:  // 4=5,4>3
                    output_tets.push( SimplexTemplateRefiner::templates + 605 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[13] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 6 );
                    break;
                case 13:  // 5>4,3=4
                    output_tets.push( SimplexTemplateRefiner::templates + 630 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 7 );
                    break;
                case 11:  // 3>4=5
                    output_tets.push( SimplexTemplateRefiner::templates + 630 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[13] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 8 );
                    break;
                case 15:  // 3=4=5
                    output_tets.push( SimplexTemplateRefiner::templates + 655 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 7, 9 );
                    break;
            }
            break;
        case 9:  // Ruprecht-Müller Case 4b
            comparison_bits = ( permlen[1] <= permlen[2] ? 1 : 0 ) | ( permlen[1] >= permlen[2] ? 2 : 0 ) |
                              ( permlen[2] <= permlen[3] ? 4 : 0 ) | ( permlen[2] >= permlen[3] ? 8 : 0 ) |
                              ( permlen[3] <= permlen[4] ? 16 : 0 ) | ( permlen[3] >= permlen[4] ? 32 : 0 ) |
                              ( permlen[1] <= permlen[4] ? 64 : 0 ) | ( permlen[1] >= permlen[4] ? 128 : 0 ) | 0;
            if( ( comparison_bits & 3 ) == 3 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[10][i] =
                        ( permuted_coords[1][i] + permuted_coords[0][i] ) * .375 + permuted_coords[2][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[1], permuted_tags[0], permuted_tags[2], permuted_tags[10] );
                permuted_hash[10] = ( *this->output_functor )( permuted_hash[1], permuted_hash[0], permuted_hash[2],
                                                               permuted_coords[10], permuted_tags[10] );
            }
            if( ( comparison_bits & 12 ) == 12 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[13][i] =
                        ( permuted_coords[2][i] + permuted_coords[3][i] ) * .375 + permuted_coords[0][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[2], permuted_tags[3], permuted_tags[0], permuted_tags[13] );
                permuted_hash[13] = ( *this->output_functor )( permuted_hash[2], permuted_hash[3], permuted_hash[0],
                                                               permuted_coords[13], permuted_tags[13] );
            }
            if( ( comparison_bits & 48 ) == 48 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[11][i] =
                        ( permuted_coords[0][i] + permuted_coords[1][i] ) * .375 + permuted_coords[3][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[0], permuted_tags[1], permuted_tags[3], permuted_tags[11] );
                permuted_hash[11] = ( *this->output_functor )( permuted_hash[0], permuted_hash[1], permuted_hash[3],
                                                               permuted_coords[11], permuted_tags[11] );
            }
            if( ( comparison_bits & 192 ) == 192 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[12][i] =
                        ( permuted_coords[2][i] + permuted_coords[3][i] ) * .375 + permuted_coords[1][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[2], permuted_tags[3], permuted_tags[1], permuted_tags[12] );
                permuted_hash[12] = ( *this->output_functor )( permuted_hash[2], permuted_hash[3], permuted_hash[1],
                                                               permuted_coords[12], permuted_tags[12] );
            }
            MB_TESSELLATOR_INCR_CASE_COUNT( 8 );
            switch( comparison_bits )
            {
                case 85:  // 2>1,3>2,4>3,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 688 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 0 );
                    break;
                case 102:  // 1>2,3>2,3>4,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 688 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 1 );
                    break;
                case 170:  // 1>2,2>3,3>4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 688 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 2 );
                    break;
                case 153:  // 2>1,2>3,4>3,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 688 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 3 );
                    break;
                case 90:  // 1>2,2>3,4>3,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 688 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[9] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 4 );
                    break;
                case 105:  // 2>1,2>3,3>4,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 688 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[7] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 5 );
                    break;
                case 165:  // 2>1,3>2,3>4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 688 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[19] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 6 );
                    break;
                case 150:  // 1>2,3>2,4>3,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 688 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[23] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 7 );
                    break;
                case 101:  // 2>1,3>2,3>4,4>1
                {
                    int alternates[] = { 713, 738, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 0, 1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 8 );
                    break;
                case 86:  // 1>2,3>2,4>3,4>1
                {
                    int alternates[] = { 713, 738, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 14, -1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 9 );
                    break;
                case 154:  // 1>2,2>3,4>3,1>4
                {
                    int alternates[] = { 713, 738, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 5, 1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 10 );
                    break;
                case 169:  // 2>1,2>3,3>4,1>4
                {
                    int alternates[] = { 713, 738, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 15, -1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 11 );
                    break;
                case 89:  // 2>1,2>3,4>3,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 763 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 12 );
                    break;
                case 166:  // 1>2,3>2,3>4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 763 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 13 );
                    break;
                case 103:  // 1=2,3>2,3>4,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 788 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 14 );
                    break;
                case 87:  // 1=2,3>2,4>3,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 788 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 15 );
                    break;
                case 185:  // 2>1,2>3,3=4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 788 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 16 );
                    break;
                case 186:  // 1>2,2>3,3=4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 788 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 17 );
                    break;
                case 158:  // 1>2,2=3,4>3,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 788 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[9] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 18 );
                    break;
                case 229:  // 2>1,3>2,3>4,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 788 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[7] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 19 );
                    break;
                case 233:  // 2>1,2>3,3>4,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 788 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[19] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 20 );
                    break;
                case 94:  // 1>2,2=3,4>3,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 788 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[23] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 21 );
                    break;
                case 155:  // 1=2,2>3,4>3,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 825 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 22 );
                    break;
                case 171:  // 1=2,2>3,3>4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 825 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 23 );
                    break;
                case 118:  // 1>2,3>2,3=4,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 825 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 24 );
                    break;
                case 117:  // 2>1,3>2,3=4,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 825 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 25 );
                    break;
                case 109:  // 2>1,2=3,3>4,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 825 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[9] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 26 );
                    break;
                case 218:  // 1>2,2>3,4>3,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 825 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[7] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 27 );
                    break;
                case 214:  // 1>2,3>2,4>3,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 825 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[19] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 28 );
                    break;
                case 173:  // 2>1,2=3,3>4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 825 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[23] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 29 );
                    break;
                case 91:  // 1=2,2>3,4>3,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 862 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 30 );
                    break;
                case 167:  // 1=2,3>2,3>4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 862 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 31 );
                    break;
                case 182:  // 1>2,3>2,3=4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 862 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 32 );
                    break;
                case 121:  // 2>1,2>3,3=4,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 862 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 33 );
                    break;
                case 93:  // 2>1,2=3,4>3,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 862 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[9] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 34 );
                    break;
                case 217:  // 2>1,2>3,4>3,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 862 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[7] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 35 );
                    break;
                case 230:  // 1>2,3>2,3>4,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 862 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[19] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 36 );
                    break;
                case 174:  // 1>2,2=3,3>4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 862 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[23] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 37 );
                    break;
                case 119:  // 1=2,3>2,3=4,4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 899 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 38 );
                    break;
                case 187:  // 1=2>3=4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 899 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 39 );
                    break;
                case 222:  // 1>2,2=3,4>3,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 899 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[9] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 40 );
                    break;
                case 237:  // 2>1,2=3,3>4,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 899 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[7] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 41 );
                    break;
                case 95:  // 4>1=2=3,4>3
                    output_tets.push( SimplexTemplateRefiner::templates + 944 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 42 );
                    break;
                case 231:  // 1=2,3>2,3>4,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 944 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 43 );
                    break;
                case 190:  // 1>2=3=4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 944 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 44 );
                    break;
                case 249:  // 2>1,2>3,3=4,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 944 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 45 );
                    break;
                case 175:  // 1=2=3>4,1>4
                    output_tets.push( SimplexTemplateRefiner::templates + 993 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 46 );
                    break;
                case 219:  // 1=2>3,4>3,1=4
                    output_tets.push( SimplexTemplateRefiner::templates + 993 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 47 );
                    break;
                case 125:  // 2>1,2=3=4>1
                    output_tets.push( SimplexTemplateRefiner::templates + 993 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 48 );
                    break;
                case 246:  // 1>2,3>2,3=4=1
                    output_tets.push( SimplexTemplateRefiner::templates + 993 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 49 );
                    break;
                case 255:  // 1=2=3=4=1
                    output_tets.push( SimplexTemplateRefiner::templates + 1042 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 8, 50 );
                    break;
            }
            break;
        case 10:  // Ruprecht-Müller Case 5
            comparison_bits = ( permlen[1] <= permlen[2] ? 1 : 0 ) | ( permlen[1] >= permlen[2] ? 2 : 0 ) |
                              ( permlen[3] <= permlen[4] ? 4 : 0 ) | ( permlen[3] >= permlen[4] ? 8 : 0 ) | 0;
            if( ( comparison_bits & 3 ) == 3 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[10][i] =
                        ( permuted_coords[1][i] + permuted_coords[0][i] ) * .375 + permuted_coords[2][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[1], permuted_tags[0], permuted_tags[2], permuted_tags[10] );
                permuted_hash[10] = ( *this->output_functor )( permuted_hash[1], permuted_hash[0], permuted_hash[2],
                                                               permuted_coords[10], permuted_tags[10] );
            }
            if( ( comparison_bits & 12 ) == 12 )
            {
                // Compute face point and tag
                for( int i = 0; i < 6; ++i )
                {
                    permuted_coords[11][i] =
                        ( permuted_coords[0][i] + permuted_coords[1][i] ) * .375 + permuted_coords[3][i] * .25;
                }
                ( *this->tag_assigner )( permuted_tags[0], permuted_tags[1], permuted_tags[3], permuted_tags[11] );
                permuted_hash[11] = ( *this->output_functor )( permuted_hash[0], permuted_hash[1], permuted_hash[3],
                                                               permuted_coords[11], permuted_tags[11] );
            }
            MB_TESSELLATOR_INCR_CASE_COUNT( 9 );
            output_tets.push( SimplexTemplateRefiner::templates + 1107 );
            output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
            output_sign.push( 1 );
            MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 0 );
            switch( comparison_bits )
            {
                case 10:  // 1>2,3>4
                    output_tets.push( SimplexTemplateRefiner::templates + 1116 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 1 );
                    break;
                case 5:  // 2>1,4>3
                    output_tets.push( SimplexTemplateRefiner::templates + 1116 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 2 );
                    break;
                case 6:  // 1>2,4>3
                {
                    int alternates[] = { 1137, 1158, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 0, 1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 3 );
                    break;
                case 9:  // 2>1,3>4
                {
                    int alternates[] = { 1137, 1158, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 14, -1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 4 );
                    break;
                case 11:  // 1=2,3>4
                {
                    int alternates[] = { 1179, 1212, 1245, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 0, 1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 5 );
                    break;
                case 7:  // 1=2,4>3
                {
                    int alternates[] = { 1179, 1212, 1245, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 14, -1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[14] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 6 );
                    break;
                case 14:  // 3=4,1>2
                {
                    int alternates[] = { 1179, 1212, 1245, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 5, 1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[5] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 7 );
                    break;
                case 13:  // 3=4,2>1
                {
                    int alternates[] = { 1179, 1212, 1245, -1 };
                    output_tets.push( SimplexTemplateRefiner::templates +
                                      this->best_tets( alternates, permuted_coords, 15, -1 ) );
                }
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[15] );
                    output_sign.push( -1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 8 );
                    break;
                case 15:  // 1=2,3=4
                    output_tets.push( SimplexTemplateRefiner::templates + 1278 );
                    output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
                    output_sign.push( 1 );
                    MB_TESSELLATOR_INCR_SUBCASE_COUNT( 9, 9 );
                    break;
            }
            break;
        case 11:  // Ruprecht-Müller Case 6
            MB_TESSELLATOR_INCR_CASE_COUNT( 10 );
            output_tets.push( SimplexTemplateRefiner::templates + 1319 );
            output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
            output_sign.push( 1 );
            MB_TESSELLATOR_INCR_SUBCASE_COUNT( 10, 0 );
            {
                int alternates[] = { 1336, 1353, 1370, -1 };
                output_tets.push( SimplexTemplateRefiner::templates +
                                  this->best_tets( alternates, permuted_coords, 0, 1 ) );
            }
            output_perm.push( SimplexTemplateRefiner::permutations_from_index[0] );
            output_sign.push( 1 );
            MB_TESSELLATOR_INCR_SUBCASE_COUNT( 10, 1 );
            break;
    }

    int* tets;
    int ntets;
    int* perm;
    int sgn;
#ifdef MB_DEBUG_TESSELLATOR
    if( output_tets.empty() )
    {
        cout << "Argh! Case " << C << " Perm " << P << " has no output!" << endl;
    }
#endif  // MB_DEBUG_TESSELLATOR
    while( !output_tets.empty() )
    {
        tets  = output_tets.top();
        ntets = *tets;
        tets++;
        perm = output_perm.top();
        sgn  = output_sign.top();

        output_tets.pop();
        output_perm.pop();
        output_sign.pop();

        int t;
        if( sgn > 0 )
        {
            for( t = 0; t < ntets; ++t )
            {
                this->refine_3_simplex( max_depth, permuted_coords[perm[tets[0]]], permuted_tags[perm[tets[0]]],
                                        permuted_hash[perm[tets[0]]], permuted_coords[perm[tets[1]]],
                                        permuted_tags[perm[tets[1]]], permuted_hash[perm[tets[1]]],
                                        permuted_coords[perm[tets[2]]], permuted_tags[perm[tets[2]]],
                                        permuted_hash[perm[tets[2]]], permuted_coords[perm[tets[3]]],
                                        permuted_tags[perm[tets[3]]], permuted_hash[perm[tets[3]]] );
                tets += 4;
            }
        }
        else
        {
            // we have an inverted tet... reverse the first 2 vertices
            // so the orientation is positive.
            for( t = 0; t < ntets; ++t )
            {
                this->refine_3_simplex( max_depth, permuted_coords[perm[tets[1]]], permuted_tags[perm[tets[1]]],
                                        permuted_hash[perm[tets[1]]], permuted_coords[perm[tets[0]]],
                                        permuted_tags[perm[tets[0]]], permuted_hash[perm[tets[0]]],
                                        permuted_coords[perm[tets[2]]], permuted_tags[perm[tets[2]]],
                                        permuted_hash[perm[tets[2]]], permuted_coords[perm[tets[3]]],
                                        permuted_tags[perm[tets[3]]], permuted_hash[perm[tets[3]]] );
                tets += 4;
            }
        }
    }

    return true;
}
bool moab::SimplexTemplateRefiner::refine_entity ( EntityType  etyp,
EntityHandle  entity 
) [virtual]

Stream a single mesh entity through the refiner.

Implements moab::EntityRefiner.

Definition at line 47 of file SimplexTemplateRefiner.cpp.

References assign_parametric_coordinates(), corner_coords, corner_handles, corner_tags, moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::RefinerTagManager::get_input_mesh(), moab::RefinerTagManager::get_input_vertex_tag(), moab::RefinerTagManager::get_number_of_vertex_tags(), moab::EntityRefiner::heap_tag_storage(), input_is_output, moab::EntityRefinerOutputFunctor::map_vertex(), moab::EntityRefiner::maximum_number_of_subdivisions, MB_SUCCESS, MBEDGE, MBEdgeParametric, MBENTITYSET, MBHEX, MBKNIFE, MBMAXTYPE, MBPOLYGON, MBPOLYHEDRON, MBPRISM, MBPYRAMID, MBQUAD, MBTET, MBTetParametric, MBTRI, MBTriParametric, MBVERTEX, MBVertexParametric, moab::EntityRefiner::output_functor, refine_0_simplex(), refine_1_simplex(), refine_2_simplex(), refine_3_simplex(), moab::EntityRefiner::reset_heap_pointers(), moab::Interface::tag_get_data(), and tag_manager.

{
    this->reset_heap_pointers();
    bool rval = true;
    const EntityHandle* conn;
    int num_nodes;
    Interface* imesh = this->tag_manager->get_input_mesh();
    if( imesh->get_connectivity( entity, conn, num_nodes ) != MB_SUCCESS )
    {
        return false;
    }
    this->corner_coords.resize( 6 * num_nodes );
    this->corner_tags.resize( num_nodes );
    this->corner_handles.resize( num_nodes );

    // Have to make num_nodes calls to get_coords() because we need xyz interleaved with rst coords.
    Tag tag_handle;
    int tag_offset;
    void* tag_data;
    for( int n = 0; n < num_nodes; ++n )
    {
        if( imesh->get_coords( &conn[n], 1, &corner_coords[6 * n + 3] ) != MB_SUCCESS )
        {
            return false;
        }
        tag_data = this->heap_tag_storage();
        for( int i = 0; i < this->tag_manager->get_number_of_vertex_tags(); ++i )
        {
            this->tag_manager->get_input_vertex_tag( i, tag_handle, tag_offset );
            if( imesh->tag_get_data( tag_handle, &conn[n], 1, (char*)tag_data + tag_offset ) != MB_SUCCESS )
            {
                return false;
            }
        }
        if( this->input_is_output )
        {
            this->corner_handles[n] = conn[n];
        }
        else
        {
            this->corner_handles[n] = this->output_functor->map_vertex( conn[n], &corner_coords[6 * n], tag_data );
#if 0
      std::cout << "#+# " << this->corner_handles[n] << " < "
        << corner_coords[ 6 * n + 3 ] << ", "
        << corner_coords[ 6 * n + 4 ] << ", "
        << corner_coords[ 6 * n + 5 ] << ">\n";
#endif  // 0
        }
        this->corner_tags[n] = tag_data;
    }

    switch( etyp )
    {
        case MBVERTEX:
            this->assign_parametric_coordinates( 1, MBVertexParametric, &this->corner_coords[0] );
            this->refine_0_simplex( &this->corner_coords[0], this->corner_tags[0], this->corner_handles[0] );
            rval = false;
            break;
        case MBEDGE:
            this->assign_parametric_coordinates( 2, MBEdgeParametric, &this->corner_coords[0] );
            rval = this->refine_1_simplex( this->maximum_number_of_subdivisions, &this->corner_coords[0],
                                           this->corner_tags[0], this->corner_handles[0], &this->corner_coords[6],
                                           this->corner_tags[1], this->corner_handles[1] );
            break;
        case MBTRI:
            this->assign_parametric_coordinates( 3, MBTriParametric, &this->corner_coords[0] );
            rval = this->refine_2_simplex( this->maximum_number_of_subdivisions, 7, &this->corner_coords[0],
                                           this->corner_tags[0], this->corner_handles[0], &this->corner_coords[6],
                                           this->corner_tags[1], this->corner_handles[1], &this->corner_coords[12],
                                           this->corner_tags[2], this->corner_handles[2] );
            break;
        case MBQUAD:
            std::cerr << "Quadrilaterals not handled yet\n";
            rval = false;
            break;
        case MBPOLYGON:
            std::cerr << "Polygons not handled yet\n";
            rval = false;
            break;
        case MBTET:
            this->assign_parametric_coordinates( 4, MBTetParametric, &this->corner_coords[0] );
            rval = this->refine_3_simplex( this->maximum_number_of_subdivisions, &this->corner_coords[0],
                                           this->corner_tags[0], this->corner_handles[0], &this->corner_coords[6],
                                           this->corner_tags[1], this->corner_handles[1], &this->corner_coords[12],
                                           this->corner_tags[2], this->corner_handles[2], &this->corner_coords[18],
                                           this->corner_tags[3], this->corner_handles[3] );
            break;
        case MBPYRAMID:
            std::cerr << "Pyramid schemes not handled yet\n";
            rval = false;
            break;
        case MBPRISM:
            std::cerr << "Prisms not handled yet\n";
            rval = false;
            break;
        case MBKNIFE:
            std::cerr << "Knifahedra not handled yet\n";
            rval = false;
            break;
        case MBHEX:
            std::cerr << "Hexahedra not handled yet\n";
            rval = false;
            break;
        case MBPOLYHEDRON:
            std::cerr << "Polyhedra not handled yet\n";
            rval = false;
            break;
        case MBENTITYSET:
            std::cerr << "How should entity sets be handled? We might iterate over its entries or "
                         "skip it."
                         "Must coordinate with MeshRefiner's loop over entities...\n";
            rval = false;
            break;
        case MBMAXTYPE:
            rval = false;
            break;
    }
    return rval;
}

Set the function object used to decide which tag values an edge or face midpoint is assigned.

This will change the tag assigner's edge size evaluator to match the refiner's.

Parameters:
[in]taThe new tag assigner. This must be non-NULL.
Return values:
Trueif the tag assigner was changed and false otherwise.

Definition at line 174 of file SimplexTemplateRefiner.cpp.

References tag_assigner.

{
    if( !ta || ta == this->tag_assigner ) return false;

    this->tag_assigner = ta;
    return true;
}

Member Data Documentation

std::vector< double > moab::SimplexTemplateRefiner::corner_coords [protected]

Definition at line 65 of file SimplexTemplateRefiner.hpp.

Referenced by refine_entity(), and SimplexTemplateRefiner().

Definition at line 67 of file SimplexTemplateRefiner.hpp.

Referenced by refine_entity(), and SimplexTemplateRefiner().

std::vector< void* > moab::SimplexTemplateRefiner::corner_tags [protected]

Definition at line 66 of file SimplexTemplateRefiner.hpp.

Referenced by refine_entity(), and SimplexTemplateRefiner().

Definition at line 71 of file SimplexTemplateRefiner.hpp.

Referenced by refine_3_simplex().

Definition at line 70 of file SimplexTemplateRefiner.hpp.

Referenced by refine_3_simplex().

int moab::SimplexTemplateRefiner::templates [static, protected]

Definition at line 72 of file SimplexTemplateRefiner.hpp.

Referenced by refine_3_simplex().

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