Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /** 00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating, 00003 * storing and accessing finite element mesh data. 00004 * 00005 * Copyright 2004 Sandia Corporation. Under the terms of Contract 00006 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 00007 * retains certain rights in 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 */ 00015 00016 // If Microsoft compiler, then WIN32 00017 #ifndef WIN32 00018 #define WIN32 00019 #endif 00020 00021 #include "moab/Core.hpp" 00022 #include "moab/Range.hpp" 00023 #include "MBTagConventions.hpp" 00024 #include "moab/ReaderWriterSet.hpp" 00025 #include "moab/ReorderTool.hpp" 00026 #include <iostream> 00027 #include <fstream> 00028 #include <sstream> 00029 #include <iomanip> 00030 #include <set> 00031 #include <list> 00032 #include <cstdlib> 00033 #include <algorithm> 00034 #ifndef WIN32 00035 #include <sys/times.h> 00036 #include <limits.h> 00037 #include <unistd.h> 00038 #endif 00039 #include <ctime> 00040 #ifdef MOAB_HAVE_MPI 00041 #include "moab/ParallelComm.hpp" 00042 #endif 00043 00044 #ifdef MOAB_HAVE_TEMPESTREMAP 00045 #include "moab/Remapping/TempestRemapper.hpp" 00046 #endif 00047 00048 #include <cstdio> 00049 00050 /* Exit values */ 00051 #define USAGE_ERROR 1 00052 #define READ_ERROR 2 00053 #define WRITE_ERROR 3 00054 #define OTHER_ERROR 4 00055 #define ENT_NOT_FOUND 5 00056 00057 using namespace moab; 00058 00059 static void print_usage( const char* name, std::ostream& stream ) 00060 { 00061 stream << "Usage: " << name 00062 << " [-a <sat_file>|-A] [-t] [subset options] [-f format] <input_file> [<input_file2> " 00063 "...] <output_file>" 00064 << std::endl 00065 << "\t-f <format> - Specify output file format" << std::endl 00066 << "\t-a <acis_file> - ACIS SAT file dumped by .cub reader (same as \"-o " 00067 "SAT_FILE=acis_file\"" 00068 << std::endl 00069 << "\t-A - .cub file reader should not dump a SAT file (depricated default)" << std::endl 00070 << "\t-o option - Specify write option." << std::endl 00071 << "\t-O option - Specify read option." << std::endl 00072 << "\t-t - Time read and write of files." << std::endl 00073 << "\t-g - Enable verbose/debug output." << std::endl 00074 << "\t-h - Print this help text and exit." << std::endl 00075 << "\t-l - List available file formats and exit." << std::endl 00076 << "\t-I <dim> - Generate internal entities of specified dimension." << std::endl 00077 #ifdef MOAB_HAVE_MPI 00078 << "\t-P - Append processor ID to output file name" << std::endl 00079 << "\t-p - Replace '%' with processor ID in input and output file name" << std::endl 00080 << "\t-M[0|1|2] - Read/write in parallel, optionally also doing " 00081 "resolve_shared_ents (1) and exchange_ghosts (2)" 00082 << std::endl 00083 << "\t-z <file> - Read metis partition information corresponding to an MPAS grid " 00084 "file and create h5m partition file" 00085 << std::endl 00086 #endif 00087 00088 #ifdef MOAB_HAVE_TEMPESTREMAP 00089 << "\t-B - Use TempestRemap exodus file reader and convert to MOAB format" << std::endl 00090 << "\t-b - Convert MOAB mesh to TempestRemap exodus file writer" << std::endl 00091 << "\t-i - Name of the global DoF tag to use with mbtempest" << std::endl 00092 << "\t-r - Order of field DoF (discretization) data; FV=1,SE=[1,N]" << std::endl 00093 #endif 00094 << "\t-- - treat all subsequent options as file names" << std::endl 00095 << "\t (allows file names beginning with '-')" << std::endl 00096 << " subset options: " << std::endl 00097 << "\tEach of the following options should be followed by " << std::endl 00098 << "\ta list of ids. IDs may be separated with commas. " << std::endl 00099 << "\tRanges of IDs may be specified with a '-' between " << std::endl 00100 << "\ttwo values. The list may not contain spaces." << std::endl 00101 << "\t-v - Volume" << std::endl 00102 << "\t-s - Surface" << std::endl 00103 << "\t-c - Curve" << std::endl 00104 << "\t-V - Vertex" << std::endl 00105 << "\t-m - Material set (block)" << std::endl 00106 << "\t-d - Dirichlet set (nodeset)" << std::endl 00107 << "\t-n - Neumann set (sideset)" << std::endl 00108 << "\t-D - Parallel partitioning set (PARALLEL_PARTITION)" << std::endl 00109 << "\tThe presence of one or more of the following flags limits " << std::endl 00110 << "\tthe exported mesh to only elements of the corresponding " << std::endl 00111 << "\tdimension. Vertices are always exported." << std::endl 00112 << "\t-1 - Edges " << std::endl 00113 << "\t-2 - Tri, Quad, Polygon " << std::endl 00114 << "\t-3 - Tet, Hex, Prism, etc. " << std::endl; 00115 } 00116 00117 static void print_help( const char* name ) 00118 { 00119 std::cout << " This program can be used to convert between mesh file\n" 00120 " formats, extract a subset of a mesh file to a separate\n" 00121 " file, or both. The type of file to write is determined\n" 00122 " from the file extension (e.g. \".vtk\") portion of the\n" 00123 " output file name.\n" 00124 " \n" 00125 " While MOAB strives to export and import all data from\n" 00126 " each supported file format, most file formats do\n" 00127 " not support MOAB's entire data model. Thus MOAB cannot\n" 00128 " guarantee lossless conversion for any file formats\n" 00129 " other than the native HDF5 representation.\n" 00130 "\n"; 00131 00132 print_usage( name, std::cout ); 00133 exit( 0 ); 00134 } 00135 00136 static void usage_error( const char* name ) 00137 { 00138 print_usage( name, std::cerr ); 00139 #ifdef MOAB_HAVE_MPI 00140 MPI_Finalize(); 00141 #endif 00142 exit( USAGE_ERROR ); 00143 } 00144 00145 static void list_formats( Interface* ); 00146 static bool parse_id_list( const char* string, std::set< int >& ); 00147 static void print_id_list( const char*, std::ostream& stream, const std::set< int >& list ); 00148 static void reset_times(); 00149 static void write_times( std::ostream& stream ); 00150 static void remove_entities_from_sets( Interface* gMB, Range& dead_entities, Range& empty_sets ); 00151 static void remove_from_vector( std::vector< EntityHandle >& vect, const Range& ents_to_remove ); 00152 static bool make_opts_string( std::vector< std::string > options, std::string& result ); 00153 static std::string percent_subst( const std::string& s, int val ); 00154 00155 static int process_partition_file( Interface* gMB, std::string& metis_partition_file ); 00156 00157 int main( int argc, char* argv[] ) 00158 { 00159 int proc_id = 0; 00160 #ifdef MOAB_HAVE_MPI 00161 MPI_Init( &argc, &argv ); 00162 MPI_Comm_rank( MPI_COMM_WORLD, &proc_id ); 00163 #endif 00164 00165 #ifdef MOAB_HAVE_TEMPESTREMAP 00166 bool tempestin = false, tempestout = false; 00167 #endif 00168 00169 Core core; 00170 Interface* gMB = &core; 00171 ErrorCode result; 00172 Range range; 00173 00174 #if( defined( MOAB_HAVE_MPI ) && defined( MOAB_HAVE_TEMPESTREMAP ) ) 00175 moab::ParallelComm* pcomm = new moab::ParallelComm( gMB, MPI_COMM_WORLD, 0 ); 00176 #endif 00177 00178 bool append_rank = false; 00179 bool percent_rank_subst = false; 00180 bool file_written = false; 00181 int i, dim; 00182 std::list< std::string >::iterator j; 00183 bool dims[4] = { false, false, false, false }; 00184 const char* format = NULL; // output file format 00185 std::list< std::string > in; // input file name list 00186 std::string out; // output file name 00187 bool verbose = false; 00188 std::set< int > geom[4], mesh[4]; // user-specified IDs 00189 std::vector< EntityHandle > set_list; // list of user-specified sets to write 00190 std::vector< std::string > write_opts, read_opts; 00191 std::string metis_partition_file; 00192 #ifdef MOAB_HAVE_TEMPESTREMAP 00193 std::string globalid_tag_name; 00194 int spectral_order = 1; 00195 #endif 00196 00197 const char* const mesh_tag_names[] = { DIRICHLET_SET_TAG_NAME, NEUMANN_SET_TAG_NAME, MATERIAL_SET_TAG_NAME, 00198 PARALLEL_PARTITION_TAG_NAME }; 00199 const char* const geom_names[] = { "VERTEX", "CURVE", "SURFACE", "VOLUME" }; 00200 00201 // scan arguments 00202 bool do_flag = true; 00203 bool print_times = false; 00204 bool generate[] = { false, false, false }; 00205 bool pval; 00206 bool parallel = false, resolve_shared = false, exchange_ghosts = false; 00207 for( i = 1; i < argc; i++ ) 00208 { 00209 if( !argv[i][0] ) usage_error( argv[0] ); 00210 00211 if( do_flag && argv[i][0] == '-' ) 00212 { 00213 if( !argv[i][1] || ( argv[i][1] != 'M' && argv[i][2] ) ) usage_error( argv[0] ); 00214 00215 switch( argv[i][1] ) 00216 { 00217 // do flag arguments: 00218 case '-': 00219 do_flag = false; 00220 break; 00221 case 'g': 00222 verbose = true; 00223 break; 00224 case 't': 00225 print_times = true; 00226 break; 00227 case 'A': 00228 break; 00229 case 'h': 00230 case 'H': 00231 print_help( argv[0] ); 00232 break; 00233 case 'l': 00234 list_formats( gMB ); 00235 break; 00236 #ifdef MOAB_HAVE_MPI 00237 case 'P': 00238 append_rank = true; 00239 break; 00240 case 'p': 00241 percent_rank_subst = true; 00242 break; 00243 case 'M': 00244 parallel = true; 00245 if( argv[i][2] == '1' || argv[i][2] == '2' ) resolve_shared = true; 00246 if( argv[i][2] == '2' ) exchange_ghosts = true; 00247 break; 00248 #endif 00249 #ifdef MOAB_HAVE_TEMPESTREMAP 00250 case 'B': 00251 tempestin = true; 00252 break; 00253 case 'b': 00254 tempestout = true; 00255 break; 00256 #endif 00257 case '1': 00258 case '2': 00259 case '3': 00260 dims[argv[i][1] - '0'] = true; 00261 break; 00262 // do options that require additional args: 00263 default: 00264 ++i; 00265 if( i == argc || argv[i][0] == '-' ) 00266 { 00267 std::cerr << "Expected argument following " << argv[i - 1] << std::endl; 00268 usage_error( argv[0] ); 00269 } 00270 if( argv[i - 1][1] == 'I' ) 00271 { 00272 dim = atoi( argv[i] ); 00273 if( dim < 1 || dim > 2 ) 00274 { 00275 std::cerr << "Invalid dimension value following -I" << std::endl; 00276 usage_error( argv[0] ); 00277 } 00278 generate[dim] = true; 00279 continue; 00280 } 00281 pval = false; 00282 switch( argv[i - 1][1] ) 00283 { 00284 case 'a': 00285 read_opts.push_back( std::string( "SAT_FILE=" ) + argv[i] ); 00286 pval = true; 00287 break; 00288 case 'f': 00289 format = argv[i]; 00290 pval = true; 00291 break; 00292 case 'o': 00293 write_opts.push_back( argv[i] ); 00294 pval = true; 00295 break; 00296 case 'O': 00297 read_opts.push_back( argv[i] ); 00298 pval = true; 00299 break; 00300 #ifdef MOAB_HAVE_TEMPESTREMAP 00301 case 'i': 00302 globalid_tag_name = std::string( argv[i] ); 00303 pval = true; 00304 break; 00305 case 'r': 00306 spectral_order = atoi( argv[i] ); 00307 pval = true; 00308 break; 00309 #endif 00310 case 'v': 00311 pval = parse_id_list( argv[i], geom[3] ); 00312 break; 00313 case 's': 00314 pval = parse_id_list( argv[i], geom[2] ); 00315 break; 00316 case 'c': 00317 pval = parse_id_list( argv[i], geom[1] ); 00318 break; 00319 case 'V': 00320 pval = parse_id_list( argv[i], geom[0] ); 00321 break; 00322 case 'D': 00323 pval = parse_id_list( argv[i], mesh[3] ); 00324 break; 00325 case 'm': 00326 pval = parse_id_list( argv[i], mesh[2] ); 00327 break; 00328 case 'n': 00329 pval = parse_id_list( argv[i], mesh[1] ); 00330 break; 00331 case 'd': 00332 pval = parse_id_list( argv[i], mesh[0] ); 00333 break; 00334 case 'z': 00335 metis_partition_file = argv[i]; 00336 pval = true; 00337 break; 00338 default: 00339 std::cerr << "Invalid option: " << argv[i] << std::endl; 00340 } 00341 00342 if( !pval ) 00343 { 00344 std::cerr << "Invalid flag or flag value: " << argv[i - 1] << " " << argv[i] << std::endl; 00345 usage_error( argv[0] ); 00346 } 00347 } 00348 } 00349 // do file names 00350 else 00351 { 00352 in.push_back( argv[i] ); 00353 } 00354 } 00355 if( in.size() < 2 ) 00356 { 00357 std::cerr << "No output file name specified." << std::endl; 00358 usage_error( argv[0] ); 00359 } 00360 // output file name is the last one specified 00361 out = in.back(); 00362 in.pop_back(); 00363 00364 if( append_rank ) 00365 { 00366 std::ostringstream mod; 00367 mod << out << "." << proc_id; 00368 out = mod.str(); 00369 } 00370 00371 if( percent_rank_subst ) 00372 { 00373 for( j = in.begin(); j != in.end(); ++j ) 00374 *j = percent_subst( *j, proc_id ); 00375 out = percent_subst( out, proc_id ); 00376 } 00377 00378 // construct options string from individual options 00379 std::string read_options, write_options; 00380 if( parallel ) 00381 { 00382 read_opts.push_back( "PARALLEL=READ_PART" ); 00383 read_opts.push_back( "PARTITION=PARALLEL_PARTITION" ); 00384 if( !append_rank && !percent_rank_subst ) write_opts.push_back( "PARALLEL=WRITE_PART" ); 00385 } 00386 if( resolve_shared ) read_opts.push_back( "PARALLEL_RESOLVE_SHARED_ENTS" ); 00387 if( exchange_ghosts ) read_opts.push_back( "PARALLEL_GHOSTS=3.0.1" ); 00388 00389 if( !make_opts_string( read_opts, read_options ) || !make_opts_string( write_opts, write_options ) ) 00390 { 00391 #ifdef MOAB_HAVE_MPI 00392 MPI_Finalize(); 00393 #endif 00394 return USAGE_ERROR; 00395 } 00396 00397 if( !metis_partition_file.empty() ) 00398 { 00399 if( ( in.size() != 1 ) || ( proc_id != 0 ) ) 00400 { 00401 std::cerr << " mpas partition allows only one input file, in serial conversion\n"; 00402 #ifdef MOAB_HAVE_MPI 00403 MPI_Finalize(); 00404 #endif 00405 return USAGE_ERROR; 00406 } 00407 } 00408 00409 Tag id_tag = gMB->globalId_tag(); 00410 00411 // Read the input file. 00412 #ifdef MOAB_HAVE_TEMPESTREMAP 00413 if( tempestin && in.size() > 1 ) 00414 { 00415 std::cerr << " we can read only one tempest files at a time\n"; 00416 #ifdef MOAB_HAVE_MPI 00417 MPI_Finalize(); 00418 #endif 00419 return USAGE_ERROR; 00420 } 00421 TempestRemapper* remapper = NULL; 00422 if( tempestin or tempestout ) 00423 { 00424 #ifdef MOAB_HAVE_MPI 00425 remapper = new moab::TempestRemapper( gMB, pcomm ); 00426 #else 00427 remapper = new moab::TempestRemapper( gMB ); 00428 #endif 00429 } 00430 00431 bool use_overlap_context = false; 00432 Tag srcParentTag, tgtParentTag; 00433 00434 #endif 00435 for( j = in.begin(); j != in.end(); ++j ) 00436 { 00437 std::string inFileName = *j; 00438 00439 reset_times(); 00440 00441 #ifdef MOAB_HAVE_TEMPESTREMAP 00442 if( remapper ) 00443 { 00444 remapper->meshValidate = false; 00445 // remapper->constructEdgeMap = true; 00446 remapper->initialize(); 00447 00448 if( tempestin ) 00449 { 00450 // convert 00451 result = remapper->LoadMesh( moab::Remapper::SourceMesh, inFileName, moab::TempestRemapper::DEFAULT );MB_CHK_ERR( result ); 00452 00453 Mesh* tempestMesh = remapper->GetMesh( moab::Remapper::SourceMesh ); 00454 tempestMesh->RemoveZeroEdges(); 00455 tempestMesh->RemoveCoincidentNodes(); 00456 00457 // Load the meshes and validate 00458 result = remapper->ConvertTempestMesh( moab::Remapper::SourceMesh ); 00459 00460 // Check if we are converting a RLL grid 00461 NcFile ncInput( inFileName.c_str(), NcFile::ReadOnly ); 00462 00463 NcError error_temp( NcError::silent_nonfatal ); 00464 // get the attribute 00465 NcAtt* attRectilinear = ncInput.get_att( "rectilinear" ); 00466 00467 // If rectilinear attribute present, mark it 00468 std::vector< int > vecDimSizes( 3, 0 ); 00469 Tag rectilinearTag; 00470 // Tag data contains: guessed mesh type, mesh size1, mesh size 2 00471 // Example: CS(0)/ICO(1)/ICOD(2), num_elements, num_nodes 00472 // : RLL(3), num_lat, num_lon 00473 result = gMB->tag_get_handle( "ClimateMetadata", 3, MB_TYPE_INTEGER, rectilinearTag, 00474 MB_TAG_SPARSE | MB_TAG_CREAT, vecDimSizes.data() );MB_CHK_SET_ERR( result, "can't create rectilinear sizes tag" ); 00475 00476 if( attRectilinear != nullptr ) 00477 { 00478 // Obtain rectilinear attributes (dimension sizes) 00479 NcAtt* attRectilinearDim0Size = ncInput.get_att( "rectilinear_dim0_size" ); 00480 NcAtt* attRectilinearDim1Size = ncInput.get_att( "rectilinear_dim1_size" ); 00481 00482 if( attRectilinearDim0Size == nullptr ) 00483 { 00484 _EXCEPTIONT( "Missing attribute \"rectilinear_dim0_size\"" ); 00485 } 00486 if( attRectilinearDim1Size == nullptr ) 00487 { 00488 _EXCEPTIONT( "Missing attribute \"rectilinear_dim1_size\"" ); 00489 } 00490 00491 int nDim0Size = attRectilinearDim0Size->as_int( 0 ); 00492 int nDim1Size = attRectilinearDim1Size->as_int( 0 ); 00493 00494 // Obtain rectilinear attributes (dimension names) 00495 NcAtt* attRectilinearDim0Name = ncInput.get_att( "rectilinear_dim0_name" ); 00496 NcAtt* attRectilinearDim1Name = ncInput.get_att( "rectilinear_dim1_name" ); 00497 00498 if( attRectilinearDim0Name == nullptr ) 00499 { 00500 _EXCEPTIONT( "Missing attribute \"rectilinear_dim0_name\"" ); 00501 } 00502 if( attRectilinearDim1Name == nullptr ) 00503 { 00504 _EXCEPTIONT( "Missing attribute \"rectilinear_dim1_name\"" ); 00505 } 00506 00507 std::string strDim0Name = attRectilinearDim0Name->as_string( 0 ); 00508 std::string strDim1Name = attRectilinearDim1Name->as_string( 0 ); 00509 00510 std::map< std::string, int > vecDimNameSizes; 00511 // Push rectilinear attributes into array 00512 vecDimNameSizes[strDim0Name] = nDim0Size; 00513 vecDimNameSizes[strDim1Name] = nDim1Size; 00514 vecDimSizes[0] = static_cast< int >( moab::TempestRemapper::RLL ); 00515 vecDimSizes[1] = vecDimNameSizes["lat"]; 00516 vecDimSizes[2] = vecDimNameSizes["lon"]; 00517 00518 printf( "Rectilinear RLL mesh size: (lat) %d X (lon) %d\n", vecDimSizes[1], vecDimSizes[2] ); 00519 00520 moab::EntityHandle mSet = 0; 00521 // mSet = remapper->GetMeshSet( moab::Remapper::SourceMesh ); 00522 result = gMB->tag_set_data( rectilinearTag, &mSet, 1, vecDimSizes.data() );MB_CHK_ERR( result ); 00523 } 00524 else 00525 { 00526 const Range& elems = remapper->GetMeshEntities( moab::Remapper::SourceMesh ); 00527 bool isQuads = elems.all_of_type( moab::MBQUAD ); 00528 bool isTris = elems.all_of_type( moab::MBTRI ); 00529 // vecDimSizes[0] = static_cast< int >( remapper->GetMeshType( moab::Remapper::SourceMesh ); 00530 vecDimSizes[0] = ( isQuads ? static_cast< int >( moab::TempestRemapper::CS ) 00531 : ( isTris ? static_cast< int >( moab::TempestRemapper::ICO ) 00532 : static_cast< int >( moab::TempestRemapper::ICOD ) ) ); 00533 vecDimSizes[1] = elems.size(); 00534 vecDimSizes[2] = remapper->GetMeshVertices( moab::Remapper::SourceMesh ).size(); 00535 00536 switch( vecDimSizes[0] ) 00537 { 00538 case 0: 00539 printf( "Cubed-Sphere mesh: %d (elems), %d (nodes)\n", vecDimSizes[1], vecDimSizes[2] ); 00540 break; 00541 case 2: 00542 printf( "Icosahedral (triangular) mesh: %d (elems), %d (nodes)\n", vecDimSizes[1], 00543 vecDimSizes[2] ); 00544 break; 00545 case 3: 00546 default: 00547 printf( "Polygonal mesh: %d (elems), %d (nodes)\n", vecDimSizes[1], vecDimSizes[2] ); 00548 break; 00549 } 00550 00551 moab::EntityHandle mSet = 0; 00552 // mSet = remapper->GetMeshSet( moab::Remapper::SourceMesh ); 00553 result = gMB->tag_set_data( rectilinearTag, &mSet, 1, vecDimSizes.data() );MB_CHK_ERR( result ); 00554 } 00555 00556 ncInput.close(); 00557 00558 const size_t nOverlapFaces = tempestMesh->faces.size(); 00559 if( tempestMesh->vecSourceFaceIx.size() == nOverlapFaces && 00560 tempestMesh->vecSourceFaceIx.size() == nOverlapFaces ) 00561 { 00562 int defaultInt = -1; 00563 use_overlap_context = true; 00564 // Check if our MOAB mesh has RED and BLUE tags; this would indicate we are 00565 // converting an overlap grid 00566 result = gMB->tag_get_handle( "TargetParent", 1, MB_TYPE_INTEGER, tgtParentTag, 00567 MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );MB_CHK_SET_ERR( result, "can't create target parent tag" ); 00568 00569 result = gMB->tag_get_handle( "SourceParent", 1, MB_TYPE_INTEGER, srcParentTag, 00570 MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );MB_CHK_SET_ERR( result, "can't create source parent tag" ); 00571 00572 const Range& faces = remapper->GetMeshEntities( moab::Remapper::SourceMesh ); 00573 00574 std::vector< int > gids( faces.size() ), srcpar( faces.size() ), tgtpar( faces.size() ); 00575 result = gMB->tag_get_data( id_tag, faces, &gids[0] );MB_CHK_ERR( result ); 00576 00577 for( unsigned ii = 0; ii < faces.size(); ++ii ) 00578 { 00579 srcpar[ii] = tempestMesh->vecSourceFaceIx[gids[ii] - 1]; 00580 tgtpar[ii] = tempestMesh->vecTargetFaceIx[gids[ii] - 1]; 00581 } 00582 00583 result = gMB->tag_set_data( srcParentTag, faces, &srcpar[0] );MB_CHK_ERR( result ); 00584 result = gMB->tag_set_data( tgtParentTag, faces, &tgtpar[0] );MB_CHK_ERR( result ); 00585 00586 srcpar.clear(); 00587 tgtpar.clear(); 00588 gids.clear(); 00589 } 00590 } 00591 else if( tempestout ) 00592 { 00593 moab::EntityHandle& srcmesh = remapper->GetMeshSet( moab::Remapper::SourceMesh ); 00594 moab::EntityHandle& ovmesh = remapper->GetMeshSet( moab::Remapper::OverlapMesh ); 00595 00596 // load the mesh in MOAB format 00597 std::vector< int > metadata(2); 00598 result = remapper->LoadNativeMesh( *j, srcmesh, metadata );MB_CHK_ERR( result ); 00599 00600 // Check if our MOAB mesh has RED and BLUE tags; this would indicate we are converting 00601 // an overlap grid 00602 ErrorCode rval1 = gMB->tag_get_handle( "SourceParent", srcParentTag ); 00603 ErrorCode rval2 = gMB->tag_get_handle( "TargetParent", tgtParentTag ); 00604 if( rval1 == MB_SUCCESS && rval2 == MB_SUCCESS ) 00605 { 00606 use_overlap_context = true; 00607 ovmesh = srcmesh; 00608 00609 Tag countTag; 00610 result = gMB->tag_get_handle( "Counting", countTag );MB_CHK_ERR( result ); 00611 00612 // Load the meshes and validate 00613 Tag order; 00614 ReorderTool reorder_tool( &core ); 00615 result = reorder_tool.handle_order_from_int_tag( srcParentTag, -1, order );MB_CHK_ERR( result ); 00616 result = reorder_tool.reorder_entities( order );MB_CHK_ERR( result ); 00617 result = gMB->tag_delete( order );MB_CHK_ERR( result ); 00618 result = remapper->ConvertMeshToTempest( moab::Remapper::OverlapMesh );MB_CHK_ERR( result ); 00619 } 00620 else 00621 { 00622 if( metadata[0] == static_cast< int >( moab::TempestRemapper::RLL ) ) 00623 { 00624 assert( metadata.size() ); 00625 std::cout << "Converting a RLL mesh with rectilinear dimension: " << metadata[0] << " X " 00626 << metadata[1] << std::endl; 00627 } 00628 00629 // Convert the mesh and validate 00630 result = remapper->ConvertMeshToTempest( moab::Remapper::SourceMesh );MB_CHK_ERR( result ); 00631 } 00632 } 00633 } 00634 else 00635 result = gMB->load_file( j->c_str(), 0, read_options.c_str() ); 00636 #else 00637 result = gMB->load_file( j->c_str(), 0, read_options.c_str() ); 00638 #endif 00639 if( MB_SUCCESS != result ) 00640 { 00641 std::cerr << "Failed to load \"" << *j << "\"." << std::endl; 00642 std::cerr << "Error code: " << gMB->get_error_string( result ) << " (" << result << ")" << std::endl; 00643 std::string message; 00644 if( MB_SUCCESS == gMB->get_last_error( message ) && !message.empty() ) 00645 std::cerr << "Error message: " << message << std::endl; 00646 #ifdef MOAB_HAVE_MPI 00647 MPI_Finalize(); 00648 #endif 00649 return READ_ERROR; 00650 } 00651 if( !proc_id ) std::cerr << "Read \"" << *j << "\"" << std::endl; 00652 if( print_times && !proc_id ) write_times( std::cout ); 00653 } 00654 00655 // Determine if the user has specified any geometry sets to write 00656 bool have_geom = false; 00657 for( dim = 0; dim <= 3; ++dim ) 00658 { 00659 if( !geom[dim].empty() ) have_geom = true; 00660 if( verbose ) print_id_list( geom_names[dim], std::cout, geom[dim] ); 00661 } 00662 00663 // True if the user has specified any sets to write 00664 bool have_sets = have_geom; 00665 00666 // Get geometry tags 00667 Tag dim_tag; 00668 if( have_geom ) 00669 { 00670 if( id_tag == 0 ) 00671 { 00672 std::cerr << "No ID tag defined." << std::endl; 00673 have_geom = false; 00674 } 00675 result = gMB->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, dim_tag ); 00676 if( MB_SUCCESS != result ) 00677 { 00678 std::cerr << "No geometry tag defined." << std::endl; 00679 have_geom = false; 00680 } 00681 } 00682 00683 // Get geometry sets 00684 if( have_geom ) 00685 { 00686 int id_val; 00687 Tag tags[] = { id_tag, dim_tag }; 00688 const void* vals[] = { &id_val, &dim }; 00689 for( dim = 0; dim <= 3; ++dim ) 00690 { 00691 int init_count = set_list.size(); 00692 for( std::set< int >::iterator iter = geom[dim].begin(); iter != geom[dim].end(); ++iter ) 00693 { 00694 id_val = *iter; 00695 range.clear(); 00696 result = gMB->get_entities_by_type_and_tag( 0, MBENTITYSET, tags, vals, 2, range ); 00697 if( MB_SUCCESS != result || range.empty() ) 00698 { 00699 range.clear(); 00700 std::cerr << geom_names[dim] << " " << id_val << " not found.\n"; 00701 } 00702 std::copy( range.begin(), range.end(), std::back_inserter( set_list ) ); 00703 } 00704 00705 if( verbose ) 00706 std::cout << "Found " << ( set_list.size() - init_count ) << ' ' << geom_names[dim] << " sets" 00707 << std::endl; 00708 } 00709 } 00710 00711 // Get mesh groupings 00712 for( i = 0; i < 4; ++i ) 00713 { 00714 if( verbose ) print_id_list( mesh_tag_names[i], std::cout, mesh[i] ); 00715 00716 if( mesh[i].empty() ) continue; 00717 have_sets = true; 00718 00719 // Get tag 00720 Tag tag; 00721 result = gMB->tag_get_handle( mesh_tag_names[i], 1, MB_TYPE_INTEGER, tag ); 00722 if( MB_SUCCESS != result ) 00723 { 00724 std::cerr << "Tag not found: " << mesh_tag_names[i] << std::endl; 00725 continue; 00726 } 00727 00728 // get entity sets 00729 int init_count = set_list.size(); 00730 for( std::set< int >::iterator iter = mesh[i].begin(); iter != mesh[i].end(); ++iter ) 00731 { 00732 range.clear(); 00733 const void* vals[] = { &*iter }; 00734 result = gMB->get_entities_by_type_and_tag( 0, MBENTITYSET, &tag, vals, 1, range ); 00735 if( MB_SUCCESS != result || range.empty() ) 00736 { 00737 range.clear(); 00738 std::cerr << mesh_tag_names[i] << " " << *iter << " not found.\n"; 00739 } 00740 std::copy( range.begin(), range.end(), std::back_inserter( set_list ) ); 00741 } 00742 00743 if( verbose ) 00744 std::cout << "Found " << ( set_list.size() - init_count ) << ' ' << mesh_tag_names[i] << " sets" 00745 << std::endl; 00746 } 00747 00748 // Check if output is limited to certain dimensions of elements 00749 bool bydim = false; 00750 for( dim = 1; dim < 4; ++dim ) 00751 if( dims[dim] ) bydim = true; 00752 00753 // Check conflicting input 00754 if( bydim ) 00755 { 00756 if( generate[1] && !dims[1] ) 00757 { 00758 std::cerr << "Warning: Request to generate 1D internal entities but not export them." << std::endl; 00759 generate[1] = false; 00760 } 00761 if( generate[2] && !dims[2] ) 00762 { 00763 std::cerr << "Warning: Request to generate 2D internal entities but not export them." << std::endl; 00764 generate[2] = false; 00765 } 00766 } 00767 00768 // Generate any internal entities 00769 if( generate[1] || generate[2] ) 00770 { 00771 EntityHandle all_mesh = 0; 00772 const EntityHandle* sets = &all_mesh; 00773 int num_sets = 1; 00774 if( have_sets ) 00775 { 00776 num_sets = set_list.size(); 00777 sets = &set_list[0]; 00778 } 00779 for( i = 0; i < num_sets; ++i ) 00780 { 00781 Range dim3, dim2, adj; 00782 gMB->get_entities_by_dimension( sets[i], 3, dim3, true ); 00783 if( generate[1] ) 00784 { 00785 gMB->get_entities_by_dimension( sets[i], 2, dim2, true ); 00786 gMB->get_adjacencies( dim3, 1, true, adj, Interface::UNION ); 00787 gMB->get_adjacencies( dim2, 1, true, adj, Interface::UNION ); 00788 } 00789 if( generate[2] ) 00790 { 00791 gMB->get_adjacencies( dim3, 2, true, adj, Interface::UNION ); 00792 } 00793 if( sets[i] ) gMB->add_entities( sets[i], adj ); 00794 } 00795 } 00796 00797 // Delete any entities not of the dimensions to be exported 00798 if( bydim ) 00799 { 00800 // Get list of dead elements 00801 Range dead_entities, tmp_range; 00802 for( dim = 1; dim <= 3; ++dim ) 00803 { 00804 if( dims[dim] ) continue; 00805 gMB->get_entities_by_dimension( 0, dim, tmp_range ); 00806 dead_entities.merge( tmp_range ); 00807 } 00808 // Remove dead entities from all sets, and add all 00809 // empty sets to list of dead entities. 00810 Range empty_sets; 00811 remove_entities_from_sets( gMB, dead_entities, empty_sets ); 00812 while( !empty_sets.empty() ) 00813 { 00814 if( !set_list.empty() ) remove_from_vector( set_list, empty_sets ); 00815 dead_entities.merge( empty_sets ); 00816 tmp_range.clear(); 00817 remove_entities_from_sets( gMB, empty_sets, tmp_range ); 00818 empty_sets = subtract( tmp_range, dead_entities ); 00819 } 00820 // Destroy dead entities 00821 gMB->delete_entities( dead_entities ); 00822 } 00823 00824 // If user specified sets to write, but none were found, exit. 00825 if( have_sets && set_list.empty() ) 00826 { 00827 std::cerr << "Nothing to write." << std::endl; 00828 #ifdef MOAB_HAVE_MPI 00829 MPI_Finalize(); 00830 #endif 00831 return ENT_NOT_FOUND; 00832 } 00833 00834 // interpret the mpas partition file created by gpmetis 00835 if( !metis_partition_file.empty() ) 00836 { 00837 int err = process_partition_file( gMB, metis_partition_file ); 00838 if( err ) 00839 { 00840 std::cerr << "Failed to process partition file \"" << metis_partition_file << "\"." << std::endl; 00841 #ifdef MOAB_HAVE_MPI 00842 MPI_Finalize(); 00843 #endif 00844 return WRITE_ERROR; 00845 } 00846 } 00847 if( verbose ) 00848 { 00849 if( have_sets ) 00850 std::cout << "Found " << set_list.size() << " specified sets to write (total)." << std::endl; 00851 else 00852 std::cout << "No sets specifed. Writing entire mesh." << std::endl; 00853 } 00854 00855 // Write the output file 00856 reset_times(); 00857 #ifdef MOAB_HAVE_TEMPESTREMAP 00858 if( remapper ) 00859 { 00860 Range faces; 00861 Mesh* tempestMesh = 00862 remapper->GetMesh( ( use_overlap_context ? moab::Remapper::OverlapMesh : moab::Remapper::SourceMesh ) ); 00863 moab::EntityHandle& srcmesh = 00864 remapper->GetMeshSet( ( use_overlap_context ? moab::Remapper::OverlapMesh : moab::Remapper::SourceMesh ) ); 00865 result = gMB->get_entities_by_dimension( srcmesh, 2, faces );MB_CHK_ERR( result ); 00866 int ntot_elements = 0, nelements = faces.size(); 00867 #ifdef MOAB_HAVE_MPI 00868 int ierr = MPI_Allreduce( &nelements, &ntot_elements, 1, MPI_INT, MPI_SUM, pcomm->comm() ); 00869 if( ierr != 0 ) MB_CHK_SET_ERR( MB_FAILURE, "MPI_Allreduce failed to get total source elements" ); 00870 #else 00871 ntot_elements = nelements; 00872 #endif 00873 00874 Tag gidTag = gMB->globalId_tag(); 00875 std::vector< int > gids( faces.size() ); 00876 result = gMB->tag_get_data( gidTag, faces, &gids[0] );MB_CHK_ERR( result ); 00877 00878 if( faces.size() > 1 && gids[0] == gids[1] && !use_overlap_context ) 00879 { 00880 #ifdef MOAB_HAVE_MPI 00881 result = pcomm->assign_global_ids( srcmesh, 2, 1, false );MB_CHK_ERR( result ); 00882 #else 00883 result = remapper->assign_vertex_element_IDs( gidTag, srcmesh, 2, 1 );MB_CHK_ERR( result ); 00884 result = remapper->assign_vertex_element_IDs( gidTag, srcmesh, 0, 1 );MB_CHK_ERR( result ); 00885 #endif 00886 } 00887 00888 // VSM: If user requested explicitly for some metadata, we need to generate the DoF ID tag 00889 // and set the appropriate numbering based on specified discretization order 00890 // Useful only for SE meshes with GLL DoFs 00891 if( spectral_order > 1 && globalid_tag_name.size() > 1 ) 00892 { 00893 result = remapper->GenerateMeshMetadata( *tempestMesh, ntot_elements, faces, NULL, globalid_tag_name, 00894 spectral_order );MB_CHK_ERR( result ); 00895 } 00896 00897 if( tempestout ) 00898 { 00899 // Check if our MOAB mesh has RED and BLUE tags; this would indicate we are converting an 00900 // overlap grid 00901 if( use_overlap_context && false ) 00902 { 00903 const int nOverlapFaces = faces.size(); 00904 // Overlap mesh: resize the source and target connection arrays 00905 tempestMesh->vecSourceFaceIx.resize( nOverlapFaces ); // 0-based indices corresponding to source mesh 00906 tempestMesh->vecTargetFaceIx.resize( nOverlapFaces ); // 0-based indices corresponding to target mesh 00907 result = gMB->tag_get_data( srcParentTag, faces, &tempestMesh->vecSourceFaceIx[0] );MB_CHK_ERR( result ); 00908 result = gMB->tag_get_data( tgtParentTag, faces, &tempestMesh->vecTargetFaceIx[0] );MB_CHK_ERR( result ); 00909 } 00910 // Write out the mesh using TempestRemap 00911 tempestMesh->Write( out, NcFile::Netcdf4 ); 00912 file_written = true; 00913 } 00914 delete remapper; // cleanup 00915 } 00916 #endif 00917 00918 if( !file_written ) 00919 { 00920 if( have_sets ) 00921 result = gMB->write_file( out.c_str(), format, write_options.c_str(), &set_list[0], set_list.size() ); 00922 else 00923 result = gMB->write_file( out.c_str(), format, write_options.c_str() ); 00924 if( MB_SUCCESS != result ) 00925 { 00926 std::cerr << "Failed to write \"" << out << "\"." << std::endl; 00927 std::cerr << "Error code: " << gMB->get_error_string( result ) << " (" << result << ")" << std::endl; 00928 std::string message; 00929 if( MB_SUCCESS == gMB->get_last_error( message ) && !message.empty() ) 00930 std::cerr << "Error message: " << message << std::endl; 00931 #ifdef MOAB_HAVE_MPI 00932 MPI_Finalize(); 00933 #endif 00934 return WRITE_ERROR; 00935 } 00936 } 00937 00938 if( !proc_id ) std::cerr << "Wrote \"" << out << "\"" << std::endl; 00939 if( print_times && !proc_id ) write_times( std::cout ); 00940 00941 #ifdef MOAB_HAVE_MPI 00942 MPI_Finalize(); 00943 #endif 00944 return 0; 00945 } 00946 00947 bool parse_id_list( const char* string, std::set< int >& results ) 00948 { 00949 bool okay = true; 00950 char* mystr = strdup( string ); 00951 for( const char* ptr = strtok( mystr, "," ); ptr; ptr = strtok( 0, "," ) ) 00952 { 00953 char* endptr; 00954 long val = strtol( ptr, &endptr, 0 ); 00955 if( endptr == ptr || val <= 0 ) 00956 { 00957 std::cerr << "Not a valid id: " << ptr << std::endl; 00958 okay = false; 00959 break; 00960 } 00961 00962 long val2 = val; 00963 if( *endptr == '-' ) 00964 { 00965 const char* sptr = endptr + 1; 00966 val2 = strtol( sptr, &endptr, 0 ); 00967 if( endptr == sptr || val2 <= 0 ) 00968 { 00969 std::cerr << "Not a valid id: " << sptr << std::endl; 00970 okay = false; 00971 break; 00972 } 00973 if( val2 < val ) 00974 { 00975 std::cerr << "Invalid id range: " << ptr << std::endl; 00976 okay = false; 00977 break; 00978 } 00979 } 00980 00981 if( *endptr ) 00982 { 00983 std::cerr << "Unexpected character: " << *endptr << std::endl; 00984 okay = false; 00985 break; 00986 } 00987 00988 for( ; val <= val2; ++val ) 00989 if( !results.insert( (int)val ).second ) std::cerr << "Warning: duplicate Id: " << val << std::endl; 00990 } 00991 00992 free( mystr ); 00993 return okay; 00994 } 00995 00996 void print_id_list( const char* head, std::ostream& stream, const std::set< int >& list ) 00997 { 00998 stream << head << ": "; 00999 01000 if( list.empty() ) 01001 { 01002 stream << "(none)" << std::endl; 01003 return; 01004 } 01005 01006 int start, prev; 01007 std::set< int >::const_iterator iter = list.begin(); 01008 start = prev = *( iter++ ); 01009 for( ;; ) 01010 { 01011 if( iter == list.end() || *iter != 1 + prev ) 01012 { 01013 stream << start; 01014 if( prev != start ) stream << '-' << prev; 01015 if( iter == list.end() ) break; 01016 stream << ", "; 01017 start = *iter; 01018 } 01019 prev = *( iter++ ); 01020 } 01021 01022 stream << std::endl; 01023 } 01024 01025 static void print_time( int clk_per_sec, const char* prefix, clock_t ticks, std::ostream& stream ) 01026 { 01027 ticks *= clk_per_sec / 100; 01028 clock_t centi = ticks % 100; 01029 clock_t seconds = ticks / 100; 01030 stream << prefix; 01031 if( seconds < 120 ) 01032 { 01033 stream << ( ticks / 100 ) << "." << centi << "s" << std::endl; 01034 } 01035 else 01036 { 01037 clock_t minutes = ( seconds / 60 ) % 60; 01038 clock_t hours = ( seconds / 3600 ); 01039 seconds %= 60; 01040 if( hours ) stream << hours << "h"; 01041 if( minutes ) stream << minutes << "m"; 01042 if( seconds || centi ) stream << seconds << "." << centi << "s"; 01043 stream << " (" << ( ticks / 100 ) << "." << centi << "s)" << std::endl; 01044 } 01045 } 01046 01047 clock_t usr_time, sys_time, abs_time; 01048 01049 #ifdef WIN32 01050 01051 void reset_times() 01052 { 01053 abs_time = clock(); 01054 } 01055 01056 void write_times( std::ostream& stream ) 01057 { 01058 clock_t abs_tm = clock(); 01059 print_time( CLOCKS_PER_SEC, " ", abs_tm - abs_time, stream ); 01060 abs_time = abs_tm; 01061 } 01062 01063 #else 01064 01065 void reset_times() 01066 { 01067 tms timebuf; 01068 abs_time = times( &timebuf ); 01069 usr_time = timebuf.tms_utime; 01070 sys_time = timebuf.tms_stime; 01071 } 01072 01073 void write_times( std::ostream& stream ) 01074 { 01075 clock_t usr_tm, sys_tm, abs_tm; 01076 tms timebuf; 01077 abs_tm = times( &timebuf ); 01078 usr_tm = timebuf.tms_utime; 01079 sys_tm = timebuf.tms_stime; 01080 print_time( sysconf( _SC_CLK_TCK ), " real: ", abs_tm - abs_time, stream ); 01081 print_time( sysconf( _SC_CLK_TCK ), " user: ", usr_tm - usr_time, stream ); 01082 print_time( sysconf( _SC_CLK_TCK ), " system: ", sys_tm - sys_time, stream ); 01083 abs_time = abs_tm; 01084 usr_time = usr_tm; 01085 sys_time = sys_tm; 01086 } 01087 01088 #endif 01089 01090 bool make_opts_string( std::vector< std::string > options, std::string& opts ) 01091 { 01092 opts.clear(); 01093 if( options.empty() ) return true; 01094 01095 // choose a separator character 01096 std::vector< std::string >::const_iterator i; 01097 char separator = '\0'; 01098 const char* alt_separators = ";+,:\t\n"; 01099 for( const char* sep_ptr = alt_separators; *sep_ptr; ++sep_ptr ) 01100 { 01101 bool seen = false; 01102 for( i = options.begin(); i != options.end(); ++i ) 01103 if( i->find( *sep_ptr, 0 ) != std::string::npos ) 01104 { 01105 seen = true; 01106 break; 01107 } 01108 if( !seen ) 01109 { 01110 separator = *sep_ptr; 01111 break; 01112 } 01113 } 01114 if( !separator ) 01115 { 01116 std::cerr << "Error: cannot find separator character for options string" << std::endl; 01117 return false; 01118 } 01119 if( separator != ';' ) 01120 { 01121 opts = ";"; 01122 opts += separator; 01123 } 01124 01125 // concatenate options 01126 i = options.begin(); 01127 opts += *i; 01128 for( ++i; i != options.end(); ++i ) 01129 { 01130 opts += separator; 01131 opts += *i; 01132 } 01133 01134 return true; 01135 } 01136 01137 void list_formats( Interface* gMB ) 01138 { 01139 const char iface_name[] = "ReaderWriterSet"; 01140 ErrorCode err; 01141 ReaderWriterSet* set = 0; 01142 ReaderWriterSet::iterator i; 01143 std::ostream& str = std::cout; 01144 01145 // get ReaderWriterSet 01146 err = gMB->query_interface( set ); 01147 if( err != MB_SUCCESS || !set ) 01148 { 01149 std::cerr << "Internal error: Interface \"" << iface_name << "\" not available.\n"; 01150 exit( OTHER_ERROR ); 01151 } 01152 01153 // get field width for format description 01154 size_t w = 0; 01155 for( i = set->begin(); i != set->end(); ++i ) 01156 if( i->description().length() > w ) w = i->description().length(); 01157 01158 // write table header 01159 str << "Format " << std::setw( w ) << std::left << "Description" 01160 << " Read Write File Name Suffixes\n" 01161 << "------ " << std::setw( w ) << std::setfill( '-' ) << "" << std::setfill( ' ' ) 01162 << " ---- ----- ------------------\n"; 01163 01164 // write table data 01165 for( i = set->begin(); i != set->end(); ++i ) 01166 { 01167 std::vector< std::string > ext; 01168 i->get_extensions( ext ); 01169 str << std::setw( 6 ) << i->name() << " " << std::setw( w ) << std::left << i->description() << " " 01170 << ( i->have_reader() ? " yes" : " no" ) << " " << ( i->have_writer() ? " yes" : " no" ) << " "; 01171 for( std::vector< std::string >::iterator j = ext.begin(); j != ext.end(); ++j ) 01172 str << " " << *j; 01173 str << std::endl; 01174 } 01175 str << std::endl; 01176 01177 gMB->release_interface( set ); 01178 exit( 0 ); 01179 } 01180 01181 void remove_entities_from_sets( Interface* gMB, Range& dead_entities, Range& empty_sets ) 01182 { 01183 empty_sets.clear(); 01184 Range sets; 01185 gMB->get_entities_by_type( 0, MBENTITYSET, sets ); 01186 for( Range::iterator i = sets.begin(); i != sets.end(); ++i ) 01187 { 01188 Range set_contents; 01189 gMB->get_entities_by_handle( *i, set_contents, false ); 01190 set_contents = intersect( set_contents, dead_entities ); 01191 gMB->remove_entities( *i, set_contents ); 01192 set_contents.clear(); 01193 gMB->get_entities_by_handle( *i, set_contents, false ); 01194 if( set_contents.empty() ) empty_sets.insert( *i ); 01195 } 01196 } 01197 01198 void remove_from_vector( std::vector< EntityHandle >& vect, const Range& ents_to_remove ) 01199 { 01200 Range::const_iterator i; 01201 std::vector< EntityHandle >::iterator j; 01202 for( i = ents_to_remove.begin(); i != ents_to_remove.end(); ++i ) 01203 { 01204 j = std::find( vect.begin(), vect.end(), *i ); 01205 if( j != vect.end() ) vect.erase( j ); 01206 } 01207 } 01208 01209 std::string percent_subst( const std::string& s, int val ) 01210 { 01211 if( s.empty() ) return s; 01212 01213 size_t j = s.find( '%' ); 01214 if( j == std::string::npos ) return s; 01215 01216 std::ostringstream st; 01217 st << s.substr( 0, j ); 01218 st << val; 01219 01220 size_t i; 01221 while( ( i = s.find( '%', j + 1 ) ) != std::string::npos ) 01222 { 01223 st << s.substr( j, i - j ); 01224 st << val; 01225 j = i; 01226 } 01227 st << s.substr( j + 1 ); 01228 return st.str(); 01229 } 01230 01231 int process_partition_file( Interface* mb, std::string& metis_partition_file ) 01232 { 01233 // how many faces in the file ? how do we make sure it is an mpas file? 01234 // mpas atmosphere files can be downloaded from here 01235 // https://mpas-dev.github.io/atmosphere/atmosphere_meshes.html 01236 Range faces; 01237 ErrorCode rval = mb->get_entities_by_dimension( 0, 2, faces );MB_CHK_ERR( rval ); 01238 std::cout << " MPAS model has " << faces.size() << " polygons\n"; 01239 01240 // read the partition file 01241 std::ifstream partfile; 01242 partfile.open( metis_partition_file.c_str() ); 01243 std::string line; 01244 std::vector< int > parts; 01245 parts.resize( faces.size(), -1 ); 01246 int i = 0; 01247 if( partfile.is_open() ) 01248 { 01249 while( getline( partfile, line ) ) 01250 { 01251 // cout << line << '\n'; 01252 parts[i++] = atoi( line.c_str() ); 01253 if( i > (int)faces.size() ) 01254 { 01255 std::cerr << " too many lines in partition file \n. bail out \n"; 01256 return 1; 01257 } 01258 } 01259 partfile.close(); 01260 } 01261 std::vector< int >::iterator pmax = max_element( parts.begin(), parts.end() ); 01262 std::vector< int >::iterator pmin = min_element( parts.begin(), parts.end() ); 01263 if( *pmin <= -1 ) 01264 { 01265 std::cerr << " partition file is incomplete, *pmin is -1 !! \n"; 01266 return 1; 01267 } 01268 std::cout << " partitions range: " << *pmin << " " << *pmax << "\n"; 01269 Tag part_set_tag; 01270 int dum_id = -1; 01271 rval = mb->tag_get_handle( "PARALLEL_PARTITION", 1, MB_TYPE_INTEGER, part_set_tag, MB_TAG_SPARSE | MB_TAG_CREAT, 01272 &dum_id );MB_CHK_ERR( rval ); 01273 01274 // get any sets already with this tag, and clear them 01275 // remove the parallel partition sets if they exist 01276 Range tagged_sets; 01277 rval = mb->get_entities_by_type_and_tag( 0, MBENTITYSET, &part_set_tag, NULL, 1, tagged_sets, Interface::UNION );MB_CHK_ERR( rval ); 01278 if( !tagged_sets.empty() ) 01279 { 01280 rval = mb->clear_meshset( tagged_sets );MB_CHK_ERR( rval ); 01281 rval = mb->tag_delete_data( part_set_tag, tagged_sets );MB_CHK_ERR( rval ); 01282 } 01283 Tag gid; 01284 rval = mb->tag_get_handle( "GLOBAL_ID", gid );MB_CHK_ERR( rval ); 01285 int num_sets = *pmax + 1; 01286 if( *pmin != 0 ) 01287 { 01288 std::cout << " problem reading parts; min is not 0 \n"; 01289 return 1; 01290 } 01291 for( i = 0; i < num_sets; i++ ) 01292 { 01293 EntityHandle new_set; 01294 rval = mb->create_meshset( MESHSET_SET, new_set );MB_CHK_ERR( rval ); 01295 tagged_sets.insert( new_set ); 01296 } 01297 int* dum_ids = new int[num_sets]; 01298 for( i = 0; i < num_sets; i++ ) 01299 dum_ids[i] = i; 01300 01301 rval = mb->tag_set_data( part_set_tag, tagged_sets, dum_ids );MB_CHK_ERR( rval ); 01302 delete[] dum_ids; 01303 01304 std::vector< int > gids; 01305 int num_faces = (int)faces.size(); 01306 gids.resize( num_faces ); 01307 rval = mb->tag_get_data( gid, faces, &gids[0] );MB_CHK_ERR( rval ); 01308 01309 for( int j = 0; j < num_faces; j++ ) 01310 { 01311 int eid = gids[j]; 01312 EntityHandle eh = faces[j]; 01313 int partition = parts[eid - 1]; 01314 if( partition < 0 || partition >= num_sets ) 01315 { 01316 std::cout << " wrong partition number \n"; 01317 return 1; 01318 } 01319 rval = mb->add_entities( tagged_sets[partition], &eh, 1 );MB_CHK_ERR( rval ); 01320 } 01321 return 0; 01322 }