MOAB: Mesh Oriented datABase  (version 5.4.1)
MBMesquite::VertexMover Class Reference

#include <VertexMover.hpp>

+ Inheritance diagram for MBMesquite::VertexMover:
+ Collaboration diagram for MBMesquite::VertexMover:

Public Member Functions

virtual ~VertexMover ()
virtual void initialize_queue (MeshDomainAssoc *mesh_and_domain, const Settings *settings, MsqError &err)
virtual double loop_over_mesh (MeshDomainAssoc *mesh_and_domain, const Settings *settings, MsqError &err)
 Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover.
virtual double loop_over_mesh (ParallelMesh *mesh, MeshDomain *domain, const Settings *settings, MsqError &err)
 Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover.
void do_nash_game_optimization ()
 Do Nash-game type optimization.
bool is_nash_game_optimization () const
 Check if optmizer will do Nash-game type optimization.
void do_block_coordinate_descent_optimization ()
 Do block coordinate descent optimization.
bool is_block_coordinate_descent_optimization () const
 Check if optmizer will do block coordinate descent type optimization.
void do_jacobi_optimization ()
 Use Jacobi iteration for optimization.
bool is_jacobi_optimization () const
 Check if optimization will use Jacobi iteration.
void do_gauss_optimization ()
 Use Gauss-Seidel iteration for optimization.
bool is_gauss_optimization () const
 Check if optimization will use Gauss-Seidel iteration.

Protected Member Functions

 VertexMover (ObjectiveFunction *OF=NULL)
virtual void initialize (PatchData &pd, MsqError &err)=0
virtual void cleanup ()=0
virtual void optimize_vertex_positions (PatchData &pd, MsqError &err)=0
virtual void initialize_mesh_iteration (PatchData &pd, MsqError &err)=0
virtual void terminate_mesh_iteration (PatchData &, MsqError &err)=0
OFEvaluatorget_objective_function_evaluator ()

Static Protected Member Functions

static TagHandle get_jacobi_coord_tag (Mesh *mesh, MsqError &err)
static void commit_jacobi_coords (TagHandle tag, Mesh *mesh, MsqError &err)

Private Attributes

OFEvaluator objFuncEval
bool jacobiOpt

Detailed Description

Base class for all Vertex Movers.

Definition at line 55 of file VertexMover.hpp.


Constructor & Destructor Documentation

Definition at line 63 of file VertexMover.cpp.

: QualityImprover(), objFuncEval( OF ), jacobiOpt( false ) {}

Definition at line 65 of file VertexMover.cpp.

{}

Member Function Documentation

void MBMesquite::VertexMover::commit_jacobi_coords ( TagHandle  tag,
Mesh mesh,
MsqError err 
) [static, protected]

Definition at line 1120 of file VertexMover.cpp.

References fixed, MBMesquite::Mesh::get_all_vertices(), MSQ_ERRRTN, MBMesquite::Mesh::tag_get_vertex_data(), MBMesquite::Vector3D::to_array(), MBMesquite::Mesh::vertex_set_coordinates(), and MBMesquite::Mesh::vertices_get_fixed_flag().

Referenced by loop_over_mesh().

{
    Vector3D coords;
    std::vector< Mesh::VertexHandle > vertices;
    mesh->get_all_vertices( vertices, err );MSQ_ERRRTN( err );
    std::vector< bool > fixed( vertices.size() );
    mesh->vertices_get_fixed_flag( &vertices[0], fixed, vertices.size(), err );
    for( size_t i = 0; i < vertices.size(); ++i )
    {
        if( !fixed[i] )
        {
            mesh->tag_get_vertex_data( tag, 1, &vertices[i], coords.to_array(), err );MSQ_ERRRTN( err );
            mesh->vertex_set_coordinates( vertices[i], coords, err );MSQ_ERRRTN( err );
        }
    }
}

Do block coordinate descent optimization.

Opposite of do_nash_game().

Definition at line 92 of file VertexMover.hpp.

Referenced by BCDTest::compare_bcd(), and run_global_smoother().

Use Gauss-Seidel iteration for optimization.

Default, opposite of do_jacobi_optimization()

Definition at line 128 of file VertexMover.hpp.

Referenced by MBMesquite::UntangleWrapper::run_wrapper().

    {
        jacobiOpt = false;
    }

Use Jacobi iteration for optimization.

Opposite of do_gauss_optimization()

Definition at line 110 of file VertexMover.hpp.

Referenced by main(), run_quality_optimizer(), and MBMesquite::UntangleWrapper::run_wrapper().

    {
        jacobiOpt = true;
    }

Do Nash-game type optimization.

Default, opposite of do_block_coordinate_descent().

Definition at line 74 of file VertexMover.hpp.

TagHandle MBMesquite::VertexMover::get_jacobi_coord_tag ( Mesh mesh,
MsqError err 
) [static, protected]

Definition at line 1057 of file VertexMover.cpp.

References MBMesquite::Mesh::DOUBLE, fixed, MBMesquite::Mesh::get_all_vertices(), MSQ_ERRZERO, MBMesquite::Mesh::tag_create(), MBMesquite::Mesh::tag_set_vertex_data(), tagname, MBMesquite::Mesh::vertices_get_coordinates(), and MBMesquite::Mesh::vertices_get_fixed_flag().

Referenced by loop_over_mesh().

{
    // Get tag handle
    const char tagname[] = "msq_jacobi_temp_coords";
    TagHandle tag        = mesh->tag_create( tagname, Mesh::DOUBLE, 3, 0, err );
    MSQ_ERRZERO( err );
    /* VertexMover will always delete the tag when it is done, so it is probably
       best not to accept an existing tag
  if (err.error_code() == TAG_ALREADY_EXISTS) {
    err.clear();
    tag = tag_get( tagname, err ); MSQ_ERRZERO(err);
    std::string name;
    Mesh::TagType type;
    unsigned length;
    mesh->tag_properties( tag, name, type, length, err ); MSQ_ERRZERO(err);
    if (type != Mesh::DOUBLE || length != 3) {
      MSQ_SETERR(err)(TAG_ALREADY_EXISTS,
                     "Tag \"%s\" already exists with invalid type",
                     tagname);
      return 0;
    }
  }
    */

    // Initialize tag value with initial vertex coordinates so that
    // vertices that never get moved end up with the correct coords.
    std::vector< Mesh::VertexHandle > vertices;
    mesh->get_all_vertices( vertices, err );
    MSQ_ERRZERO( err );
    // remove fixed vertices
    // to avoid really huge arrays (especially since we need to copy
    // coords out of annoying MsqVertex class to double array), work
    // in blocks
    const size_t blocksize = 4096;
    std::vector< bool > fixed( blocksize );
    MsqVertex coords[blocksize];
    double tag_data[3 * blocksize];
    for( size_t i = 0; i < vertices.size(); i += blocksize )
    {
        size_t count = std::min( blocksize, vertices.size() - i );
        // remove fixed vertices
        mesh->vertices_get_fixed_flag( &vertices[i], fixed, count, err );
        MSQ_ERRZERO( err );
        size_t w = 0;
        for( size_t j = 0; j < count; ++j )
            if( !fixed[j] ) vertices[i + w++] = vertices[i + j];
        count = w;
        // store tag data for free vertices
        mesh->vertices_get_coordinates( &vertices[i], coords, count, err );
        MSQ_ERRZERO( err );
        for( size_t j = 0; j < count; ++j )
        {
            tag_data[3 * j]     = coords[j][0];
            tag_data[3 * j + 1] = coords[j][1];
            tag_data[3 * j + 2] = coords[j][2];
        }
        mesh->tag_set_vertex_data( tag, count, &vertices[i], tag_data, err );
        MSQ_ERRZERO( err );
    }

    return tag;
}
void MBMesquite::VertexMover::initialize_queue ( MeshDomainAssoc mesh_and_domain,
const Settings settings,
MsqError err 
) [virtual]

Called for all instructions in queue before loop_over_mesh is called for any insetruction in queue. Default behavior is to do nothing.

Reimplemented from MBMesquite::QualityImprover.

Definition at line 1051 of file VertexMover.cpp.

References MBMesquite::OFEvaluator::initialize_queue(), MSQ_ERRRTN, and objFuncEval.

{
    QualityImprover::initialize_queue( mesh_and_domain, settings, err );MSQ_ERRRTN( err );
    objFuncEval.initialize_queue( mesh_and_domain, settings, err );MSQ_ERRRTN( err );
}

Check if optmizer will do block coordinate descent type optimization.

Default, opposite of is_nash_game_optimization().

Definition at line 101 of file VertexMover.hpp.

Check if optimization will use Gauss-Seidel iteration.

Default, opposite of is_jacobi_optimization()

Definition at line 137 of file VertexMover.hpp.

    {
        return !jacobiOpt;
    }

Check if optimization will use Jacobi iteration.

Opposite of is_gauss_optimization()

Definition at line 119 of file VertexMover.hpp.

    {
        return jacobiOpt;
    }

Check if optmizer will do Nash-game type optimization.

Default, opposite of is_block_coordinate_descent_optimization().

Definition at line 83 of file VertexMover.hpp.

    {
        return objFuncEval.is_nash_game();
    }
double MBMesquite::VertexMover::loop_over_mesh ( MeshDomainAssoc mesh_and_domain,
const Settings settings,
MsqError err 
) [virtual]

Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover.

Parameters:
constMeshSet &: this MeshSet is looped over. Only the mutable data members are changed (such as currentVertexInd).

Implements MBMesquite::Instruction.

Definition at line 129 of file VertexMover.cpp.

References MBMesquite::TerminationCriterion::accumulate_outer(), MBMesquite::TerminationCriterion::accumulate_patch(), MBMesquite::TerminationCriterion::add_iteration_limit(), MBMesquite::PatchData::attach_settings(), cleanup(), MBMesquite::TerminationCriterion::cleanup(), commit_jacobi_coords(), coord_tag, MBMesquite::TerminationCriterion::criterion_is_set(), MBMesquite::TerminationCriterion::cull_vertices(), MBMesquite::TerminationCriterion::cull_vertices_global(), ERROR, MBMesquite::TMPQualityMetric::evaluate(), MBMesquite::MeshDomainAssoc::get_domain(), MBMesquite::QualityMetric::get_evaluations(), MBMesquite::QualityImprover::get_inner_termination_criterion(), get_jacobi_coord_tag(), MBMesquite::MeshDomainAssoc::get_mesh(), MBMesquite::OFEvaluator::get_objective_function(), get_objective_function_evaluator(), MBMesquite::QualityImprover::get_outer_termination_criterion(), MBMesquite::get_parallel_rank(), MBMesquite::PatchSet::get_patch(), MBMesquite::PatchSet::get_patch_handles(), MBMesquite::QualityImprover::get_patch_set(), MBMesquite::ElementAvgQM::get_quality_metric(), MBMesquite::ElementMaxQM::get_quality_metric(), MBMesquite::ElementPMeanP::get_quality_metric(), MBMesquite::ObjectiveFunctionTemplate::get_quality_metric(), MBMesquite::TQualityMetric::get_target_metric(), MBMesquite::OFEvaluator::initialize(), initialize(), initialize_mesh_iteration(), MBMesquite::Instruction::initialize_vertex_byte(), MBMesquite::MsqError::INVALID_MESH, MBMesquite::MsqError::INVALID_STATE, jacobiOpt, mesh, MSQ_CHKERR, MSQ_ERRZERO, MSQ_SETERR, optimize_vertex_positions(), MBMesquite::OFEvaluator::reset(), MBMesquite::TerminationCriterion::reset_inner(), MBMesquite::TerminationCriterion::reset_outer(), MBMesquite::TerminationCriterion::reset_patch(), MBMesquite::TerminationCriterion::set_debug_output_level(), MBMesquite::PatchData::set_domain(), MBMesquite::PatchSet::set_mesh(), MBMesquite::PatchData::set_mesh(), MBMesquite::PatchData::set_mesh_entities(), MBMesquite::Mesh::tag_delete(), MBMesquite::TerminationCriterion::terminate(), terminate_mesh_iteration(), and MBMesquite::PatchData::update_mesh().

{
    Mesh* mesh         = mesh_and_domain->get_mesh();
    MeshDomain* domain = mesh_and_domain->get_domain();

    TagHandle coord_tag      = 0;  // store uncommitted coords for jacobi optimization
    TagHandle* coord_tag_ptr = 0;

    TerminationCriterion* outer_crit = 0;
    TerminationCriterion* inner_crit = 0;

    // Clear culling flag, set hard fixed flag, etc on all vertices
    initialize_vertex_byte( mesh_and_domain, settings, err );
    MSQ_ERRZERO( err );

    // Get the patch data to use for the first iteration
    OFEvaluator& obj_func = get_objective_function_evaluator();

    // Check for impromer use of MaxTemplate
    ObjectiveFunctionTemplate* maxt_ptr = dynamic_cast< MaxTemplate* >( obj_func.get_objective_function() );
    if( maxt_ptr )
    {
        QualityImprover* ngqi_ptr = dynamic_cast< NonGradient* >( this );
        if( !ngqi_ptr )
            std::cout << "Warning: MaxTemplate results in non-differentiable objective function." << std::endl
                      << "   Therefore, it is best to use the NonGradient solver. Other Mesquite" << std::endl
                      << "   solvers require derivative information." << std::endl;
    }

    PatchData patch;
    patch.set_mesh( mesh );
    patch.set_domain( domain );
    if( settings ) patch.attach_settings( settings );
    bool one_patch = false, inner_crit_terminated, all_culled;
    std::vector< Mesh::VertexHandle > patch_vertices;
    std::vector< Mesh::ElementHandle > patch_elements;
    bool valid;

    PatchSet* patch_set = get_patch_set();
    if( !patch_set )
    {
        MSQ_SETERR( err )( "No PatchSet for QualityImprover!", MsqError::INVALID_STATE );
        return 0.0;
    }
    patch_set->set_mesh( mesh );

    std::vector< PatchSet::PatchHandle > patch_list;
    patch_set->get_patch_handles( patch_list, err );
    MSQ_ERRZERO( err );

    // check for inverted elements when using a barrietr target metric
    TQualityMetric* tqm_ptr        = NULL;
    TMetricBarrier* tm_ptr         = NULL;
    AWMetricBarrier* awm_ptr       = NULL;
    ElemSampleQM* sample_qm_ptr    = NULL;
    QualityMetric* qm_ptr          = NULL;
    TQualityMetric* pmeanp_ptr     = NULL;
    ElementMaxQM* elem_max_ptr     = NULL;
    ElementAvgQM* elem_avg_ptr     = NULL;
    ElementPMeanP* elem_pmeanp_ptr = NULL;

    ObjectiveFunctionTemplate* of_ptr = dynamic_cast< ObjectiveFunctionTemplate* >( obj_func.get_objective_function() );
    if( of_ptr ) qm_ptr = of_ptr->get_quality_metric();
    if( qm_ptr )
    {
        pmeanp_ptr      = dynamic_cast< TQualityMetric* >( qm_ptr );  // PMeanP case
        elem_max_ptr    = dynamic_cast< ElementMaxQM* >( qm_ptr );
        elem_avg_ptr    = dynamic_cast< ElementAvgQM* >( qm_ptr );
        elem_pmeanp_ptr = dynamic_cast< ElementPMeanP* >( qm_ptr );
    }
    if( elem_max_ptr )
        sample_qm_ptr = elem_max_ptr->get_quality_metric();
    else if( elem_pmeanp_ptr )
        sample_qm_ptr = elem_pmeanp_ptr->get_quality_metric();
    else if( elem_avg_ptr )
        sample_qm_ptr = elem_avg_ptr->get_quality_metric();
    else if( pmeanp_ptr )
    {
        tm_ptr  = dynamic_cast< TMetricBarrier* >( pmeanp_ptr->get_target_metric() );
        awm_ptr = dynamic_cast< AWMetricBarrier* >( pmeanp_ptr->get_target_metric() );
    }

    if( sample_qm_ptr || pmeanp_ptr )
    {
        if( !pmeanp_ptr )
        {
            tqm_ptr = dynamic_cast< TQualityMetric* >( sample_qm_ptr );
            if( tqm_ptr )
            {
                tm_ptr  = dynamic_cast< TMetricBarrier* >( tqm_ptr->get_target_metric() );
                awm_ptr = dynamic_cast< AWMetricBarrier* >( tqm_ptr->get_target_metric() );
            }
        }
        else
        {
            tqm_ptr = dynamic_cast< TQualityMetric* >( pmeanp_ptr );
        }

        if( tqm_ptr && ( tm_ptr || awm_ptr ) )
        {
            // check for inverted elements
            this->initialize( patch, err );
            std::vector< size_t > handles;

            // set up patch data
            std::vector< PatchSet::PatchHandle >::iterator patch_iter = patch_list.begin();
            while( patch_iter != patch_list.end() )
            {
                do
                {
                    patch_set->get_patch( *patch_iter, patch_elements, patch_vertices, err );
                    if( MSQ_CHKERR( err ) ) goto ERROR;
                    ++patch_iter;
                } while( patch_elements.empty() && patch_iter != patch_list.end() );

                patch.set_mesh_entities( patch_elements, patch_vertices, err );
                if( MSQ_CHKERR( err ) ) goto ERROR;

                qm_ptr->get_evaluations( patch, handles, true, err );  // MSQ_ERRFALSE(err);

                // do actual check for inverted elements
                std::vector< size_t >::const_iterator i;
                double tvalue;
                for( i = handles.begin(); i != handles.end(); ++i )
                {
                    bool result = tqm_ptr->evaluate( patch, *i, tvalue, err );
                    if( MSQ_CHKERR( err ) || !result ) return false;  // inverted element detected
                }
            }
        }
    }

    // Get termination criteria
    outer_crit = this->get_outer_termination_criterion();
    inner_crit = this->get_inner_termination_criterion();
    if( outer_crit == 0 )
    {
        MSQ_SETERR( err )( "Termination Criterion pointer is Null", MsqError::INVALID_STATE );
        return 0.;
    }
    if( inner_crit == 0 )
    {
        MSQ_SETERR( err )
        ( "Termination Criterion pointer for inner loop is Null", MsqError::INVALID_STATE );
        return 0.;
    }

    // Set Termination Criterion defaults if no other Criterion is set
    if( !outer_crit->criterion_is_set() ) outer_crit->add_iteration_limit( 1 );
    if( !inner_crit->criterion_is_set() ) inner_crit->add_iteration_limit( 10 );

    // If using a local patch, suppress output of inner termination criterion
    if( patch_list.size() > 1 )
        inner_crit->set_debug_output_level( 3 );
    else
        one_patch = true;

    if( jacobiOpt )
    {
        coord_tag = get_jacobi_coord_tag( mesh, err );
        MSQ_ERRZERO( err );
        coord_tag_ptr = &coord_tag;
    }

    // Initialize outer loop

    this->initialize( patch, err );
    if( MSQ_CHKERR( err ) ) goto ERROR;

    valid = obj_func.initialize( mesh_and_domain, settings, patch_set, err );
    if( MSQ_CHKERR( err ) ) goto ERROR;
    if( !valid )
    {
        MSQ_SETERR( err )
        ( "ObjectiveFunction initialization failed.  Mesh "
          "invalid at one or more sample points.",
          MsqError::INVALID_MESH );
        goto ERROR;
    }

    outer_crit->reset_outer( mesh, domain, obj_func, settings, err );
    if( MSQ_CHKERR( err ) ) goto ERROR;

    // if only one patch, get the patch now
    if( one_patch )
    {
        patch_set->get_patch( patch_list[0], patch_elements, patch_vertices, err );
        if( MSQ_CHKERR( err ) ) goto ERROR;
        patch.set_mesh_entities( patch_elements, patch_vertices, err );
        if( MSQ_CHKERR( err ) ) goto ERROR;
    }

    // Loop until outer termination criterion is met
    inner_crit_terminated = false;
    while( !outer_crit->terminate() )
    {
        if( inner_crit_terminated )
        {
            MSQ_SETERR( err )
            ( "Inner termiation criterion satisfied for all patches "
              "without meeting outer termination criterion.  This is "
              "an infinite loop.  Aborting.",
              MsqError::INVALID_STATE );
            break;
        }
        inner_crit_terminated = true;
        all_culled            = true;

        int num_patches = 0;
        // Loop over each patch
        std::vector< PatchSet::PatchHandle >::iterator p_iter = patch_list.begin();
        while( p_iter != patch_list.end() )
        {
            if( !one_patch )
            {  // if only one patch (global) re-use the previous one
                // loop until we get a non-empty patch.  patch will be empty
                // for culled vertices with element-on-vertex patches
                do
                {
                    patch_set->get_patch( *p_iter, patch_elements, patch_vertices, err );
                    if( MSQ_CHKERR( err ) ) goto ERROR;
                    ++p_iter;
                } while( patch_elements.empty() && p_iter != patch_list.end() );

                if( patch_elements.empty() )
                {  // no more non-culled vertices
                    if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk all vertices culled." << std::endl;
                    break;
                }

                all_culled = false;
                patch.set_mesh_entities( patch_elements, patch_vertices, err );
                if( MSQ_CHKERR( err ) ) goto ERROR;
            }
            else
            {
                ++p_iter;
                all_culled = false;
            }

            ++num_patches;

            // Initialize for inner iteration

            this->initialize_mesh_iteration( patch, err );
            if( MSQ_CHKERR( err ) ) goto ERROR;

            obj_func.reset();

            outer_crit->reset_patch( patch, err );
            if( MSQ_CHKERR( err ) ) goto ERROR;

            inner_crit->reset_inner( patch, obj_func, err );
            if( MSQ_CHKERR( err ) ) goto ERROR;

            inner_crit->reset_patch( patch, err );
            if( MSQ_CHKERR( err ) ) goto ERROR;

            // Don't even call optimizer if inner termination
            // criterion has already been met.
            if( !inner_crit->terminate() )
            {
                inner_crit_terminated = false;

                // Call optimizer - should loop on inner_crit->terminate()
                this->optimize_vertex_positions( patch, err );
                if( MSQ_CHKERR( err ) ) goto ERROR;

                // Update for changes during inner iteration
                // (during optimizer loop)

                outer_crit->accumulate_patch( patch, err );
                if( MSQ_CHKERR( err ) ) goto ERROR;

                inner_crit->cull_vertices( patch, obj_func, err );
                if( MSQ_CHKERR( err ) ) goto ERROR;

                // FIXME
                if( 0 )
                {
                    inner_crit->cull_vertices_global( patch, mesh, domain, settings, obj_func, err );
                    if( MSQ_CHKERR( err ) ) goto ERROR;
                }

                patch.update_mesh( err, coord_tag_ptr );
                if( MSQ_CHKERR( err ) ) goto ERROR;
            }
        }

        if( jacobiOpt ) commit_jacobi_coords( coord_tag, mesh, err );

        this->terminate_mesh_iteration( patch, err );
        if( MSQ_CHKERR( err ) ) goto ERROR;

        outer_crit->accumulate_outer( mesh, domain, obj_func, settings, err );
        if( MSQ_CHKERR( err ) ) goto ERROR;

        if( all_culled ) break;
    }

ERROR:
    if( jacobiOpt ) mesh->tag_delete( coord_tag, err );

    // call the criteria's cleanup funtions.
    if( outer_crit ) outer_crit->cleanup( mesh, domain, err );
    if( inner_crit ) inner_crit->cleanup( mesh, domain, err );
    // call the optimization cleanup function.
    this->cleanup();

    return 0.;
}
double MBMesquite::VertexMover::loop_over_mesh ( ParallelMesh mesh,
MeshDomain domain,
const Settings settings,
MsqError err 
) [virtual]

Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover.

Parameters:
constMeshSet &: this MeshSet is looped over. Only the mutable data members are changed (such as currentVertexInd).

[email protected] 1/19/12: the logic here was changed so that all proc's must agree on the values used for outer and inner termination before the iteration is stopped. Previously, the ParallelHelper::communicate_all_true method returned true if any proc sent it a true value, which seems to be a bug, at least in the name of the method. The method has been changed to return true only if all proc's values are true. In the previous version, this meant that if any proc hit its inner or outer termination criterion, the loop was exited, and thus some parts of the mesh are potentially left unconverged. Also, if the outer criterion was satisfied on part of the mesh (say a uniform part), the iterations were not executed at all. Also, changed name of "did_some" to "inner_crit_terminated", and flipped its boolean value to be consistent with the name - for readability and for correctness since we want to communicate a true value through the helper.

*** smooth the interior ***////

[email protected] save vertex bytes since boundary smoothing changes them

*** smooth the boundary ***////

[email protected] restore vertex bytes since boundary smoothing changes them

Reimplemented from MBMesquite::Instruction.

Definition at line 479 of file VertexMover.cpp.

References MBMesquite::TerminationCriterion::accumulate_outer(), MBMesquite::TerminationCriterion::accumulate_patch(), MBMesquite::PatchData::attach_settings(), MBMesquite::checkpoint_bytes(), cleanup(), MBMesquite::TerminationCriterion::cleanup(), commit_jacobi_coords(), MBMesquite::ParallelHelper::communicate_all_true(), MBMesquite::ParallelHelper::communicate_any_true(), MBMesquite::ParallelHelper::communicate_first_independent_set(), MBMesquite::ParallelHelper::communicate_next_independent_set(), MBMesquite::ParallelHelper::compute_first_independent_set(), MBMesquite::ParallelHelper::compute_next_independent_set(), coord_tag, MBMesquite::TerminationCriterion::cull_vertices(), MBMesquite::TerminationCriterion::cull_vertices_global(), MBMesquite::MsqDebug::disable_all(), MBMesquite::MsqError::error_message(), MBMesquite::Mesh::get_all_vertices(), MBMesquite::QualityImprover::get_inner_termination_criterion(), get_jacobi_coord_tag(), MBMesquite::ParallelHelper::get_next_partition_boundary_vertex(), get_objective_function_evaluator(), MBMesquite::QualityImprover::get_outer_termination_criterion(), MBMesquite::get_parallel_rank(), MBMesquite::PatchSet::get_patch(), MBMesquite::PatchSet::get_patch_handles(), MBMesquite::QualityImprover::get_patch_set(), MBMesquite::TerminationCriterion::globalInvertedCount, MBMesquite::OFEvaluator::initialize(), initialize(), initialize_mesh_iteration(), MBMesquite::Instruction::initialize_vertex_byte(), MBMesquite::MsqError::INVALID_STATE, jacobiOpt, MSQ_CHKERR, MSQ_DBG, MSQ_ERRZERO, MSQ_SETERR, optimize_vertex_positions(), MBMesquite::MsqError::PARALLEL_ERROR, MBMesquite::TerminationCriterion::patchInvertedCount, PERROR_COND, MBMesquite::OFEvaluator::reset(), MBMesquite::TerminationCriterion::reset_inner(), MBMesquite::TerminationCriterion::reset_outer(), MBMesquite::TerminationCriterion::reset_patch(), MBMesquite::restore_bytes(), MBMesquite::save_or_restore_debug_state(), MBMesquite::TerminationCriterion::set_debug_output_level(), MBMesquite::PatchData::set_domain(), MBMesquite::PatchSet::set_mesh(), MBMesquite::PatchData::set_mesh(), MBMesquite::PatchData::set_mesh_entities(), MBMesquite::ParallelHelper::smoothing_close(), MBMesquite::ParallelHelper::smoothing_init(), MBMesquite::Mesh::tag_delete(), MBMesquite::TerminationCriterion::terminate(), terminate_mesh_iteration(), MBMesquite::PatchData::update_mesh(), and MBMesquite::Mesh::vertices_get_attached_elements().

{
    std::vector< size_t > junk;
    Mesh::VertexHandle vertex_handle;
    TagHandle coord_tag      = 0;  // store uncommitted coords for jacobi optimization
    TagHandle* coord_tag_ptr = 0;
    int outer_iter           = 0;
    int inner_iter           = 0;
    bool one_patch           = false;

    // Clear culling flag, set hard fixed flag, etc on all vertices
    MeshDomainAssoc mesh_and_domain = MeshDomainAssoc( (Mesh*)mesh, 0 );
    initialize_vertex_byte( &mesh_and_domain, settings, err );
    MSQ_ERRZERO( err );

    // Get the patch data to use for the first iteration
    OFEvaluator& obj_func = get_objective_function_evaluator();

    PatchData patch;
    patch.set_mesh( (Mesh*)mesh );
    patch.set_domain( domain );
    patch.attach_settings( settings );

    ParallelHelper* helper = mesh->get_parallel_helper();
    if( !helper )
    {
        MSQ_SETERR( err )( "No ParallelHelper instance", MsqError::INVALID_STATE );
        return 0;
    }

    helper->smoothing_init( err );
    MSQ_ERRZERO( err );

    bool inner_crit_terminated, all_culled;
    std::vector< Mesh::VertexHandle > patch_vertices;
    std::vector< Mesh::ElementHandle > patch_elements;
    std::vector< Mesh::VertexHandle > fixed_vertices;
    std::vector< Mesh::VertexHandle > free_vertices;

    // Get termination criteria
    TerminationCriterion* outer_crit = this->get_outer_termination_criterion();
    TerminationCriterion* inner_crit = this->get_inner_termination_criterion();
    if( outer_crit == 0 )
    {
        MSQ_SETERR( err )( "Termination Criterion pointer is Null", MsqError::INVALID_STATE );
        return 0.;
    }
    if( inner_crit == 0 )
    {
        MSQ_SETERR( err )
        ( "Termination Criterion pointer for inner loop is Null", MsqError::INVALID_STATE );
        return 0.;
    }

    PatchSet* patch_set = get_patch_set();
    if( !patch_set )
    {
        MSQ_SETERR( err )( "No PatchSet for QualityImprover!", MsqError::INVALID_STATE );
        return 0.0;
    }
    patch_set->set_mesh( (Mesh*)mesh );

    std::vector< PatchSet::PatchHandle > patch_list;
    patch_set->get_patch_handles( patch_list, err );
    MSQ_ERRZERO( err );

    if( patch_list.size() > 1 )
        inner_crit->set_debug_output_level( 3 );
    else
        one_patch = true;

    if( jacobiOpt )
    {
        coord_tag = get_jacobi_coord_tag( mesh, err );
        MSQ_ERRZERO( err );
        coord_tag_ptr = &coord_tag;
    }

    // parallel error checking
    MsqError perr;
    bool pdone = false;

#define PERROR_COND continue

    // Initialize outer loop

    this->initialize( patch, err );
    if( MSQ_CHKERR( err ) )
    {
        MSQ_SETERR( perr )( "initialize patch", MsqError::INVALID_STATE );
    }  // goto ERROR;

    MeshDomainAssoc mesh_and_domain2 = MeshDomainAssoc( (Mesh*)mesh, domain );
    obj_func.initialize( &mesh_and_domain2, settings, patch_set, err );
    if( MSQ_CHKERR( err ) )
    {
        MSQ_SETERR( perr )( "initialize obj_func", MsqError::INVALID_STATE );
    }  // goto ERROR;

    outer_crit->reset_outer( (Mesh*)mesh, domain, obj_func, settings, err );
    if( MSQ_CHKERR( err ) )
    {
        MSQ_SETERR( perr )( "reset_outer", MsqError::INVALID_STATE );
    }  // goto ERROR;

    // Loop until outer termination criterion is met
    inner_crit_terminated = false;
    all_culled            = false;
    for( ;; )
    {
        if( 0 )
            std::cout << "P[" << get_parallel_rank() << "] tmp srk inner_iter= " << inner_iter
                      << " outer_iter= " << outer_iter << std::endl;

        // PERROR:

        if( MSQ_CHKERR( perr ) )
        {
            std::cout << "P[" << get_parallel_rank() << "] VertexMover::loop_over_mesh found parallel error: " << perr
                      << "\n quitting... pdone= " << pdone << std::endl;
            pdone = true;
        }

        helper->communicate_any_true( pdone, err );

        if( 0 )
            std::cout << "P[" << get_parallel_rank() << "] tmp srk inner_iter= " << inner_iter
                      << " outer_iter= " << outer_iter << " pdone= " << pdone << std::endl;

        if( pdone )
        {
            std::cout << "P[" << get_parallel_rank()
                      << "] VertexMover::loop_over_mesh found parallel error, quitting... pdone= " << pdone
                      << std::endl;
            MSQ_SETERR( err )( "PARALLEL ERROR", MsqError::PARALLEL_ERROR );
            break;
        }

        ++outer_iter;

        /// [email protected] 1/19/12: the logic here was changed so that all proc's must agree
        ///   on the values used for outer and inner termination before the iteration is stopped.
        ///   Previously, the ParallelHelper::communicate_all_true method returned true if any
        ///   proc sent it a true value, which seems to be a bug, at least in the name of the
        ///   method. The method has been changed to return true only if all proc's values are true.
        ///   In the previous version, this meant that if any proc hit its inner or outer
        ///   termination criterion, the loop was exited, and thus some parts of the mesh
        ///   are potentially left unconverged.  Also, if the outer criterion was satisfied on
        ///   part of the mesh (say a uniform part), the iterations were not executed at all.
        /// Also, changed name of "did_some" to "inner_crit_terminated", and flipped its boolean
        ///   value to be consistent with the name - for readability and for correctness since
        ///   we want to communicate a true value through the helper.

        bool outer_crit_terminated       = outer_crit->terminate();
        bool outer_crit_terminated_local = outer_crit_terminated;
        helper->communicate_all_true( outer_crit_terminated, err );

        bool inner_crit_terminated_local = inner_crit_terminated;
        helper->communicate_all_true( inner_crit_terminated, err );

        bool all_culled_local = all_culled;
        helper->communicate_all_true( all_culled, err );

        bool done = all_culled || outer_crit_terminated;
        if( inner_crit_terminated )
        {
            MSQ_SETERR( err )
            ( "Inner termination criterion satisfied for all patches "
              "without meeting outer termination criterion.  This is "
              "an infinite loop.  Aborting.",
              MsqError::INVALID_STATE );
            done = true;
            helper->communicate_any_true( done, err );
        }

        bool local_done = done;

        helper->communicate_all_true( done, err );

        if( 0 )
            std::cout << "P[" << get_parallel_rank() << "] tmp srk done= " << done << " local_done= " << local_done
                      << " all_culled= " << all_culled << " outer_crit->terminate()= " << outer_crit->terminate()
                      << " outer_term= " << outer_crit_terminated
                      << " outer_term_local= " << outer_crit_terminated_local
                      << " inner_crit_terminated = " << inner_crit_terminated
                      << " inner_crit_terminated_local = " << inner_crit_terminated_local
                      << " all_culled = " << all_culled << " all_culled_local = " << all_culled_local << std::endl;

        if( MSQ_CHKERR( err ) )
        {
            MSQ_SETERR( perr )( "loop start", MsqError::INVALID_STATE );
        }  // goto ERROR;

        if( done ) break;

        inner_crit_terminated = true;
        all_culled            = true;

        ///*** smooth the interior ***////

        // get the fixed vertices (i.e. the ones *not* part of the first independent set)
        helper->compute_first_independent_set( fixed_vertices );

        // sort the fixed vertices
        std::sort( fixed_vertices.begin(), fixed_vertices.end() );

        // Loop over each patch
        if( 0 && MSQ_DBG( 2 ) )
            std::cout << "P[" << get_parallel_rank() << "] tmp srk number of patches = " << patch_list.size()
                      << " inner_iter= " << inner_iter << " outer_iter= " << outer_iter
                      << " inner.globalInvertedCount = " << inner_crit->globalInvertedCount
                      << " outer.globalInvertedCount = " << outer_crit->globalInvertedCount
                      << " inner.patchInvertedCount = " << inner_crit->patchInvertedCount
                      << " outer.patchInvertedCount = " << outer_crit->patchInvertedCount << std::endl;

        save_or_restore_debug_state( true );
        // MsqDebug::disable_all();

        int num_patches = 0;

        std::vector< PatchSet::PatchHandle >::iterator p_iter = patch_list.begin();
        while( p_iter != patch_list.end() )
        {

            // loop until we get a non-empty patch.  patch will be empty
            // for culled vertices with element-on-vertex patches
            do
            {
                patch_set->get_patch( *p_iter, patch_elements, patch_vertices, err );
                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( "get_patch", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;
                ++p_iter;
            } while( patch_elements.empty() && p_iter != patch_list.end() );

            if( patch_elements.empty() )
            {  // no more non-culled vertices
                if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk all vertices culled." << std::endl;
                break;
            }

            if( patch_vertices.empty() )  // global patch hack (means all mesh vertices)
            {
                mesh->get_all_vertices( patch_vertices, err );
            }

            free_vertices.clear();

            for( size_t i = 0; i < patch_vertices.size(); ++i )
                if( !std::binary_search( fixed_vertices.begin(), fixed_vertices.end(), patch_vertices[i] ) )
                    free_vertices.push_back( patch_vertices[i] );

            if( free_vertices.empty() )
            {  // all vertices were fixed -> skip patch
                continue;
            }

            ++num_patches;
            all_culled = false;
            patch.set_mesh_entities( patch_elements, free_vertices, err );
            if( MSQ_CHKERR( err ) )
            {
                MSQ_SETERR( perr )( "set_mesh_entities", MsqError::INVALID_STATE );
                PERROR_COND;
            }  // goto ERROR;

            // Initialize for inner iteration

            this->initialize_mesh_iteration( patch, err );
            if( MSQ_CHKERR( err ) )
            {
                MSQ_SETERR( perr )( "initialize_mesh_iteration", MsqError::INVALID_STATE );
                PERROR_COND;
            }  // goto ERROR;

            obj_func.reset();

            outer_crit->reset_patch( patch, err );
            if( MSQ_CHKERR( err ) )
            {
                MSQ_SETERR( perr )( "reset_patch outer", MsqError::INVALID_STATE );
                PERROR_COND;
            }  // goto ERROR;

            inner_crit->reset_inner( patch, obj_func, err );
            if( MSQ_CHKERR( err ) )
            {
                MSQ_SETERR( perr )( "reset_inner", MsqError::INVALID_STATE );
                PERROR_COND;
            }  // goto ERROR;

            inner_crit->reset_patch( patch, err );
            if( MSQ_CHKERR( err ) )
            {
                MSQ_SETERR( perr )( "inner reset_patch", MsqError::INVALID_STATE );
                PERROR_COND;
            }  // goto ERROR;

            // Don't even call optimizer if inner termination
            // criterion has already been met.
            if( !inner_crit->terminate() )
            {
                inner_crit_terminated = false;
                if( one_patch ) ++inner_iter;

                // Call optimizer - should loop on inner_crit->terminate()
                // size_t num_vert=patch.num_free_vertices();
                // std::cout << "P[" << get_parallel_rank() << "] tmp srk VertexMover num_vert= " <<
                // num_vert << std::endl;

                this->optimize_vertex_positions( patch, err );
                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( "optimize_vertex_positions", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;

                // Update for changes during inner iteration
                // (during optimizer loop)

                outer_crit->accumulate_patch( patch, err );
                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( "outer accumulate_patch", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;

                inner_crit->cull_vertices( patch, obj_func, err );
                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( "inner cull_vertices", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;

                // experimental...
                if( 0 )
                {
                    inner_crit->cull_vertices_global( patch, mesh, domain, settings, obj_func, err );
                    if( MSQ_CHKERR( err ) )
                    {
                        MSQ_SETERR( perr )( "cull_vertices_global", MsqError::INVALID_STATE );
                        PERROR_COND;
                    }  // goto ERROR;
                }

                patch.update_mesh( err, coord_tag_ptr );
                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( "update_mesh", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;
            }
        }  // while(p_iter....

        save_or_restore_debug_state( false );

        if( 1 )
        {
            bool pdone_inner = false;

            if( MSQ_CHKERR( perr ) )
            {
                std::cout << "P[" << get_parallel_rank()
                          << "] VertexMover::loop_over_mesh found parallel error: " << perr
                          << "\n quitting... pdone_inner= " << pdone_inner << std::endl;
                pdone_inner = true;
            }

            helper->communicate_any_true( pdone_inner, err );

            if( 0 )
                std::cout << "P[" << get_parallel_rank() << "] tmp srk inner_iter= " << inner_iter
                          << " outer_iter= " << outer_iter << " pdone_inner= " << pdone_inner << std::endl;

            if( pdone_inner )
            {
                if( 0 )
                    std::cout << "P[" << get_parallel_rank()
                              << "] tmp srk found parallel error, quitting... pdone_inner= " << pdone_inner
                              << std::endl;
                MSQ_SETERR( err )( "PARALLEL ERROR", MsqError::PARALLEL_ERROR );
                break;
            }
        }

        /// [email protected] save vertex bytes since boundary smoothing changes them
        std::vector< unsigned char > saved_bytes;
        checkpoint_bytes( mesh, saved_bytes, err );
        if( MSQ_CHKERR( err ) )
        {
            MSQ_SETERR( perr )( "checkpoint_bytes ", MsqError::INVALID_STATE );
            PERROR_COND;
        }  // goto ERROR;

        helper->communicate_first_independent_set( err );
        if( MSQ_CHKERR( err ) )
        {
            MSQ_SETERR( perr )( "communicate_first_independent_set ", MsqError::INVALID_STATE );
            PERROR_COND;
        }  // goto ERROR;

        ///*** smooth the boundary ***////
        save_or_restore_debug_state( true );
        MsqDebug::disable_all();

        while( helper->compute_next_independent_set() )
        {
            // Loop over all boundary elements
            while( helper->get_next_partition_boundary_vertex( vertex_handle ) )
            {

                patch_vertices.clear();
                patch_vertices.push_back( vertex_handle );
                patch_elements.clear();
                mesh->vertices_get_attached_elements( &vertex_handle, 1, patch_elements, junk, err );

                all_culled = false;
                patch.set_mesh_entities( patch_elements, patch_vertices, err );

                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( "set_mesh_entities 2 ", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;

                // Initialize for inner iteration

                this->initialize_mesh_iteration( patch, err );
                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( " initialize_mesh_iteration 2", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;

                obj_func.reset();

                outer_crit->reset_patch( patch, err );
                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( "outer reset_patch 2 ", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;

                inner_crit->reset_inner( patch, obj_func, err );
                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( " inner reset_inner 2", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;

                inner_crit->reset_patch( patch, err );
                if( MSQ_CHKERR( err ) )
                {
                    MSQ_SETERR( perr )( " inner_crit reset_patch 2", MsqError::INVALID_STATE );
                    PERROR_COND;
                }  // goto ERROR;

                // Don't even call optimizer if inner termination
                // criterion has already been met.
                if( !inner_crit->terminate() )
                {
                    inner_crit_terminated = false;

                    // Call optimizer - should loop on inner_crit->terminate()
                    this->optimize_vertex_positions( patch, err );
                    if( MSQ_CHKERR( err ) )
                    {
                        MSQ_SETERR( perr )
                        ( " optimize_vertex_positions 2", MsqError::INVALID_STATE );
                        PERROR_COND;
                    }  // goto ERROR;

                    // Update for changes during inner iteration
                    // (during optimizer loop)

                    outer_crit->accumulate_patch( patch, err );
                    if( MSQ_CHKERR( err ) )
                    {
                        MSQ_SETERR( perr )( " outer accumulate_patch 2", MsqError::INVALID_STATE );
                        PERROR_COND;
                    }  // goto ERROR;

                    inner_crit->cull_vertices( patch, obj_func, err );
                    if( MSQ_CHKERR( err ) )
                    {
                        MSQ_SETERR( perr )( " inner cull_vertices", MsqError::INVALID_STATE );
                        PERROR_COND;
                    }  // goto ERROR;

                    // FIXME
                    if( 0 )
                    {
                        inner_crit->cull_vertices_global( patch, mesh, domain, settings, obj_func, err );
                        if( MSQ_CHKERR( err ) )
                        {
                            MSQ_SETERR( perr )
                            ( " cull_vertices_global 2 ", MsqError::INVALID_STATE );
                            PERROR_COND;
                        }  // goto ERROR;
                    }

                    patch.update_mesh( err, coord_tag_ptr );
                    if( MSQ_CHKERR( err ) )
                    {
                        MSQ_SETERR( perr )( " update_mesh 2", MsqError::INVALID_STATE );
                        PERROR_COND;
                    }  // goto ERROR;
                }
            }
            helper->communicate_next_independent_set( err );
            if( MSQ_CHKERR( err ) )
            {
                MSQ_SETERR( perr )
                ( " communicate_next_independent_set 2", MsqError::INVALID_STATE );
                PERROR_COND;
            }  // goto ERROR;
        }      // while(helper->compute_next_independent_set())

        save_or_restore_debug_state( false );

        // if (!get_parallel_rank())
        // std::cout << "P[" << get_parallel_rank() << "] tmp srk num_patches= " << num_patches <<
        // std::endl;

        /// [email protected] restore vertex bytes since boundary smoothing changes them
        restore_bytes( mesh, saved_bytes, err );
        if( MSQ_CHKERR( err ) )
        {
            MSQ_SETERR( perr )( " restore_bytes", MsqError::INVALID_STATE );
            PERROR_COND;
        }  // goto ERROR;

        if( jacobiOpt ) commit_jacobi_coords( coord_tag, mesh, err );

        this->terminate_mesh_iteration( patch, err );
        if( MSQ_CHKERR( err ) )
        {
            MSQ_SETERR( perr )( " terminate_mesh_iteration", MsqError::INVALID_STATE );
            PERROR_COND;
        }  // goto ERROR;

        outer_crit->accumulate_outer( mesh, domain, obj_func, settings, err );
        if( MSQ_CHKERR( err ) )
        {
            MSQ_SETERR( perr )( " outer_crit accumulate_outer", MsqError::INVALID_STATE );
            PERROR_COND;
        }  // goto ERROR;
    }

    // ERROR:

    if( MSQ_CHKERR( err ) )
    {
        std::cout << "P[" << get_parallel_rank() << "] VertexMover::loop_over_mesh error = " << err.error_message()
                  << std::endl;
    }

    if( jacobiOpt ) mesh->tag_delete( coord_tag, err );

    // call the criteria's cleanup funtions.
    outer_crit->cleanup( mesh, domain, err );MSQ_CHKERR( err );
    inner_crit->cleanup( mesh, domain, err );MSQ_CHKERR( err );
    // call the optimization cleanup function.
    this->cleanup();
    // close the helper
    helper->smoothing_close( err );MSQ_CHKERR( err );

    return 0.;
}

Member Data Documentation

Definition at line 161 of file VertexMover.hpp.

Referenced by loop_over_mesh().

Definition at line 160 of file VertexMover.hpp.

Referenced by initialize_queue().

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