MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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