MOAB: Mesh Oriented datABase  (version 5.4.1)
DeformingDomainWrapper.cpp
Go to the documentation of this file.
00001 /* *****************************************************************
00002     MESQUITE -- The Mesh Quality Improvement Toolkit
00003 
00004     Copyright 2010 Sandia National Laboratories.  Developed at the
00005     University of Wisconsin--Madison under SNL contract number
00006     624796.  The U.S. Government and the University of Wisconsin
00007     retain certain rights to this software.
00008 
00009     This library is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU Lesser General Public
00011     License as published by the Free Software Foundation; either
00012     version 2.1 of the License, or (at your option) any later version.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     (lgpl.txt) along with this library; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 
00023     (2010) [email protected]
00024 
00025   ***************************************************************** */
00026 
00027 /** \file DeformingDomainWrapper.cpp
00028  *  \brief Implement DeformingDomainWrapper class
00029  *  \author Jason Kraftcheck
00030  */
00031 
00032 #include "DeformingDomainWrapper.hpp"
00033 #include "TagVertexMesh.hpp"
00034 #include "ReferenceMesh.hpp"
00035 #include "RefMeshTargetCalculator.hpp"
00036 #include "InstructionQueue.hpp"
00037 #include "QualityImprover.hpp"
00038 #include "SteepestDescent.hpp"
00039 #include "TerminationCriterion.hpp"
00040 #include "PMeanPTemplate.hpp"
00041 #include "ElementPMeanP.hpp"
00042 #include "TQualityMetric.hpp"
00043 #include "TMixed.hpp"
00044 #include "TShapeNB1.hpp"
00045 #include "TShapeSize2DNB1.hpp"
00046 #include "TShapeSize3DNB1.hpp"
00047 #include "TShapeSizeOrientNB1.hpp"
00048 #include "MeshInterface.hpp"
00049 #include "MsqError.hpp"
00050 #include "MsqVertex.hpp"
00051 #include "QualityAssessor.hpp"
00052 #include "CurveDomain.hpp"
00053 
00054 #include <numeric>  // for std::accumulate
00055 
00056 namespace MBMesquite
00057 {
00058 
00059 const DeformingDomainWrapper::MeshCharacteristic DEFAULT_METRIC_TYPE = DeformingDomainWrapper::SHAPE;
00060 
00061 const bool DEFAULT_CULLING                              = true;
00062 const double DEFAULT_CPU_TIME                           = 0.0;
00063 const double DEFAULT_MOVEMENT_FACTOR                    = 0.01;
00064 const int DEFAULT_INNER_ITERATIONS                      = 2;
00065 const char DEFAULT_CURVE_TAG[]                          = "MesquiteCurveFraction";
00066 const DeformingCurveSmoother::Scheme DEFAULT_CURVE_TYPE = DeformingCurveSmoother::PROPORTIONAL;
00067 
00068 DeformingDomainWrapper::DeformingDomainWrapper()
00069     : metricType( DEFAULT_METRIC_TYPE ), initVertexCoords( "" ), doCulling( DEFAULT_CULLING ),
00070       cpuTime( DEFAULT_CPU_TIME ), movementFactor( DEFAULT_MOVEMENT_FACTOR )
00071 {
00072 }
00073 
00074 DeformingDomainWrapper::~DeformingDomainWrapper() {}
00075 
00076 void DeformingDomainWrapper::store_initial_mesh( Mesh* mesh, MsqError& err )
00077 {
00078     TagVertexMesh tool( err, mesh, false, initVertexCoords );MSQ_ERRRTN( err );
00079     InstructionQueue q;
00080     q.add_tag_vertex_mesh( &tool, err );MSQ_ERRRTN( err );
00081     q.run_instructions( mesh, err );MSQ_ERRRTN( err );
00082     if( initVertexCoords.empty() ) initVertexCoords = tool.get_tag_name();
00083 }
00084 
00085 void DeformingDomainWrapper::set_vertex_movement_limit_factor( double f )
00086 {
00087     assert( f > 0.0 );
00088     movementFactor = f;
00089 }
00090 
00091 void DeformingDomainWrapper::run_wrapper( MeshDomainAssoc* mesh_and_domain,
00092                                           ParallelMesh* pmesh,
00093                                           Settings* settings,
00094                                           QualityAssessor* qa,
00095                                           MsqError& err )
00096 {
00097     if( movementFactor <= 0 )
00098     {
00099         MSQ_SETERR( err )
00100         ( MsqError::INVALID_STATE, "Optimization will not terminate with non-positive movement factor %f",
00101           movementFactor );
00102         return;
00103     }
00104 
00105     Mesh* mesh       = mesh_and_domain->get_mesh();
00106     MeshDomain* geom = mesh_and_domain->get_domain();
00107 
00108     // Move initial mesh to domain in case caller did not
00109     move_to_domain( mesh, geom, err );MSQ_ERRRTN( err );
00110 
00111     const double P = 1.0;
00112     TagVertexMesh init_mesh( err, mesh );MSQ_ERRRTN( err );
00113     ReferenceMesh ref_mesh( &init_mesh );
00114     RefMeshTargetCalculator W( &ref_mesh );
00115 
00116     TShapeNB1 mu_s;
00117     TShapeSize2DNB1 mu_2d_ss;
00118     TShapeSize3DNB1 mu_3d_ss;
00119     TMixed mu_ss( &mu_2d_ss, &mu_3d_ss );
00120     TShapeSizeOrientNB1 mu_sso;
00121     TMetric* mu = 0;
00122     switch( metricType )
00123     {
00124         case SHAPE:
00125             mu = &mu_s;
00126             break;
00127         case SHAPE_SIZE:
00128             mu = &mu_ss;
00129             break;
00130         case SHAPE_SIZE_ORIENT:
00131             mu = &mu_sso;
00132             break;
00133     }
00134 
00135     TQualityMetric sample_metric( &W, mu );
00136     ElementPMeanP elem_metric( P, &sample_metric );
00137     PMeanPTemplate obj_func( P, &elem_metric );
00138 
00139     TerminationCriterion inner, outer;
00140     SteepestDescent improver( &obj_func );
00141     improver.use_element_on_vertex_patch();  // Nash optimization
00142     inner.add_iteration_limit( DEFAULT_INNER_ITERATIONS );
00143     if( doCulling )
00144         inner.cull_on_absolute_vertex_movement_edge_length( movementFactor );
00145     else
00146         outer.add_absolute_vertex_movement_edge_length( movementFactor );
00147     if( cpuTime > 0.0 ) outer.add_cpu_time( cpuTime );
00148     improver.set_inner_termination_criterion( &inner );
00149     improver.set_outer_termination_criterion( &outer );
00150 
00151     qa->add_quality_assessment( &elem_metric );
00152     InstructionQueue q;
00153     q.add_quality_assessor( qa, err );MSQ_ERRRTN( err );
00154     q.set_master_quality_improver( &improver, err );MSQ_ERRRTN( err );
00155     q.add_quality_assessor( qa, err );MSQ_ERRRTN( err );
00156     q.run_common( mesh_and_domain, pmesh, settings, err );MSQ_ERRRTN( err );
00157 }
00158 
00159 void DeformingDomainWrapper::move_to_domain( Mesh* mesh, MeshDomain* geom, MsqError& err )
00160 {
00161     std::vector< Mesh::VertexHandle > verts;
00162     mesh->get_all_vertices( verts, err );MSQ_ERRRTN( err );
00163 
00164     MsqVertex coords;
00165     std::vector< Mesh::VertexHandle >::const_iterator i;
00166     for( i = verts.begin(); i != verts.end(); ++i )
00167     {
00168         mesh->vertices_get_coordinates( &*i, &coords, 1, err );MSQ_ERRRTN( err );
00169         geom->snap_to( *i, coords );
00170         mesh->vertex_set_coordinates( *i, coords, err );MSQ_ERRRTN( err );
00171     }
00172 }
00173 
00174 DeformingCurveSmoother::DeformingCurveSmoother() : metricType( DEFAULT_CURVE_TYPE ), initFractTag( DEFAULT_CURVE_TAG )
00175 {
00176 }
00177 
00178 DeformingCurveSmoother::~DeformingCurveSmoother() {}
00179 
00180 void DeformingCurveSmoother::store_initial_mesh( Mesh* mesh,
00181                                                  const Mesh::VertexHandle* verts,
00182                                                  int nverts,
00183                                                  CurveDomain*,
00184                                                  MsqError& err )
00185 {
00186     if( nverts < 2 )
00187     {
00188         MSQ_SETERR( err )
00189         ( "Invalid curve mesh.  Need at least two end vertices.", MsqError::INVALID_MESH );
00190         return;
00191     }
00192 
00193     // get edge lengths
00194     std::vector< double > vals( nverts - 1 );
00195     MsqVertex coords[2];
00196     int prev = 0;
00197     mesh->vertices_get_coordinates( verts, coords + prev, 1, err );MSQ_ERRRTN( err );
00198     for( int i = 1; i < nverts; ++i )
00199     {
00200         int next = 1 - prev;
00201         mesh->vertices_get_coordinates( verts + i, coords + next, 1, err );MSQ_ERRRTN( err );
00202         vals[i - 1] = ( coords[0] - coords[1] ).length();
00203         prev        = next;
00204     }
00205 
00206     // convert to length fraction before each iterior vertex
00207     // (sum of lengths of adjacent edges over total curve length)
00208     const double total = std::accumulate( vals.begin(), vals.end(), 0.0 );
00209     for( int i = 1; i < nverts - 1; ++i )
00210         vals[i - 1] = vals[i - 1] / total;
00211     vals.resize( nverts - 2 );
00212 
00213     // create tag
00214     TagHandle tag = mesh->tag_create( initFractTag, Mesh::DOUBLE, 1, 0, err );
00215     if( err.error_code() == MsqError::TAG_ALREADY_EXISTS )
00216     {
00217         err.clear();
00218         tag = get_tag( mesh, err );
00219     }
00220     MSQ_ERRRTN( err );
00221 
00222     // store tag data on interior vertices
00223     mesh->tag_set_vertex_data( tag, nverts - 2, verts + 1, &vals[0], err );MSQ_ERRRTN( err );
00224 }
00225 
00226 void DeformingCurveSmoother::smooth_curve( Mesh* mesh,
00227                                            const Mesh::VertexHandle* verts,
00228                                            int nverts,
00229                                            CurveDomain* geom,
00230                                            Scheme,
00231                                            MsqError& err )
00232 {
00233     if( nverts < 2 )
00234     {
00235         MSQ_SETERR( err )
00236         ( "Invalid curve mesh.  Need at least two end vertices.", MsqError::INVALID_MESH );
00237         return;
00238     }
00239 
00240     // Verify that end vertices are on curve.  We cannot snap end vertices
00241     // to ends of curve for application because we don't know where the
00242     // ends of the curve are.
00243     MsqVertex coords[2], coords2;
00244     Mesh::VertexHandle ends[2] = { verts[0], verts[nverts - 1] };
00245     for( int i = 0; i < 2; ++i )
00246     {
00247         mesh->vertices_get_coordinates( ends + i, coords + i, 1, err );MSQ_ERRRTN( err );
00248         geom->position_from_length( coords[i].to_array(), 0, coords2.to_array(), err );MSQ_ERRRTN( err );
00249         if( ( coords[i] - coords2 ).length_squared() > DBL_EPSILON )
00250         {
00251             MSQ_SETERR( err )
00252             ( "Curve end vertices do not line on curve.  Move ends to curve end points first", MsqError::INVALID_MESH );
00253             return;
00254         }
00255     }
00256     const double total = geom->arc_length( coords[0].to_array(), coords[1].to_array(), err );MSQ_ERRRTN( err );
00257 
00258     std::vector< double > vals( nverts - 1 );
00259     if( metricType == EQUAL )
00260     {
00261         std::fill( vals.begin(), vals.end(), 1.0 / ( nverts - 1 ) );
00262         // fracsum = 1.0;
00263     }
00264     else
00265     {  // metricType == PROPORTIONAL
00266         TagHandle tag = get_tag( mesh, err );MSQ_ERRRTN( err );
00267         mesh->tag_get_vertex_data( tag, nverts - 2, verts + 1, &vals[0], err );MSQ_ERRRTN( err );
00268         double sum = std::accumulate( vals.begin(), vals.end() - 1, 0.0 );
00269         if( 1.0 - sum > 1e-8 )
00270             vals.back() = 1.0 - sum;
00271         else
00272         {
00273             vals.back() = *std::min_element( vals.begin(), vals.end() - 1 );
00274             sum += vals.back();
00275             for( size_t i = 0; i < vals.size(); ++i )
00276                 vals[i] /= sum;
00277         }
00278     }
00279 
00280     double frac_sum = 0.0;
00281     for( int i = 1; i < nverts - 1; ++i )
00282     {
00283         frac_sum += vals[i - 1];
00284         geom->position_from_length( coords[0].to_array(), total * frac_sum, coords[1].to_array(), err );MSQ_ERRRTN( err );
00285         mesh->vertex_set_coordinates( verts[i], coords[1], err );MSQ_ERRRTN( err );
00286     }
00287 }
00288 
00289 TagHandle DeformingCurveSmoother::get_tag( Mesh* mesh, MsqError& err )
00290 {
00291     TagHandle h = mesh->tag_get( initFractTag, err );
00292     MSQ_ERRZERO( err );
00293     std::string name;
00294     Mesh::TagType type;
00295     unsigned len;
00296     mesh->tag_properties( h, name, type, len, err );
00297     MSQ_ERRZERO( err );
00298     if( type != Mesh::DOUBLE || len != 1 )
00299     {
00300         MSQ_SETERR( err )
00301         ( MsqError::INVALID_MESH, "Tag \"%s\" exists but is not 1 double value per vertex.", initFractTag.c_str() );
00302     }
00303     return h;
00304 }
00305 
00306 }  // namespace MBMesquite
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines