Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
convert.cpp File Reference
#include "moab/Core.hpp"
#include "moab/Range.hpp"
#include "MBTagConventions.hpp"
#include "moab/ReaderWriterSet.hpp"
#include "moab/ReorderTool.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <set>
#include <list>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cstdio>
+ Include dependency graph for convert.cpp:

Go to the source code of this file.

Macros

#define WIN32
 
#define USAGE_ERROR   1
 
#define READ_ERROR   2
 
#define WRITE_ERROR   3
 
#define OTHER_ERROR   4
 
#define ENT_NOT_FOUND   5
 

Functions

static void print_usage (const char *name, std::ostream &stream)
 
static void print_help (const char *name)
 
static void usage_error (const char *name)
 
static void list_formats (Interface *)
 
static bool parse_id_list (const char *string, std::set< int > &)
 
static void print_id_list (const char *, std::ostream &stream, const std::set< int > &list)
 
static void reset_times ()
 
static void write_times (std::ostream &stream)
 
static void remove_entities_from_sets (Interface *gMB, Range &dead_entities, Range &empty_sets)
 
static void remove_from_vector (std::vector< EntityHandle > &vect, const Range &ents_to_remove)
 
static bool make_opts_string (std::vector< std::string > options, std::string &result)
 
static std::string percent_subst (const std::string &s, int val)
 
static int process_partition_file (Interface *gMB, std::string &metis_partition_file)
 
int main (int argc, char *argv[])
 
static void print_time (int clk_per_sec, const char *prefix, clock_t ticks, std::ostream &stream)
 

Variables

clock_t usr_time
 
clock_t sys_time
 
clock_t abs_time
 

Macro Definition Documentation

◆ ENT_NOT_FOUND

#define ENT_NOT_FOUND   5

Definition at line 57 of file convert.cpp.

◆ OTHER_ERROR

#define OTHER_ERROR   4

Definition at line 56 of file convert.cpp.

◆ READ_ERROR

#define READ_ERROR   2

Definition at line 54 of file convert.cpp.

◆ USAGE_ERROR

#define USAGE_ERROR   1

Definition at line 53 of file convert.cpp.

◆ WIN32

#define WIN32

MOAB, a Mesh-Oriented datABase, is a software component for creating, storing and accessing finite element mesh data.

Copyright 2004 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

Definition at line 18 of file convert.cpp.

◆ WRITE_ERROR

#define WRITE_ERROR   3

Definition at line 55 of file convert.cpp.

Function Documentation

◆ list_formats()

void list_formats ( Interface gMB)
static

Definition at line 1284 of file convert.cpp.

1285 {
1286  const char iface_name[] = "ReaderWriterSet";
1287  ErrorCode err;
1288  ReaderWriterSet* set = 0;
1290  std::ostream& str = std::cout;
1291 
1292  // get ReaderWriterSet
1293  err = gMB->query_interface( set );
1294  if( err != MB_SUCCESS || !set )
1295  {
1296  std::cerr << "Internal error: Interface \"" << iface_name << "\" not available.\n";
1297  exit( OTHER_ERROR );
1298  }
1299 
1300  // get field width for format description
1301  size_t w = 0;
1302  for( i = set->begin(); i != set->end(); ++i )
1303  if( i->description().length() > w ) w = i->description().length();
1304 
1305  // write table header
1306  str << "Format " << std::setw( w ) << std::left << "Description" << " Read Write File Name Suffixes\n"
1307  << "------ " << std::setw( w ) << std::setfill( '-' ) << "" << std::setfill( ' ' )
1308  << " ---- ----- ------------------\n";
1309 
1310  // write table data
1311  for( i = set->begin(); i != set->end(); ++i )
1312  {
1313  std::vector< std::string > ext;
1314  i->get_extensions( ext );
1315  str << std::setw( 6 ) << i->name() << " " << std::setw( w ) << std::left << i->description() << " "
1316  << ( i->have_reader() ? " yes" : " no" ) << " " << ( i->have_writer() ? " yes" : " no" ) << " ";
1317  for( std::vector< std::string >::iterator j = ext.begin(); j != ext.end(); ++j )
1318  str << " " << *j;
1319  str << std::endl;
1320  }
1321  str << std::endl;
1322 
1323  gMB->release_interface( set );
1324  exit( 0 );
1325 }

References moab::ReaderWriterSet::begin(), moab::ReaderWriterSet::end(), ErrorCode, gMB, MB_SUCCESS, OTHER_ERROR, moab::Interface::query_interface(), and moab::Interface::release_interface().

Referenced by main().

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 168 of file convert.cpp.

169 {
170  int proc_id = 0;
171 #ifdef MOAB_HAVE_MPI
172  MPI_Init( &argc, &argv );
173  MPI_Comm_rank( MPI_COMM_WORLD, &proc_id );
174 #endif
175 
176 #ifdef MOAB_HAVE_TEMPESTREMAP
177  bool tempestin = false, tempestout = false;
178 #endif
179 
180  Core core;
181  Interface* gMB = &core;
182  ErrorCode result;
183  Range range;
184 
185 #if ( defined( MOAB_HAVE_MPI ) && defined( MOAB_HAVE_TEMPESTREMAP ) )
186  moab::ParallelComm* pcomm = new moab::ParallelComm( gMB, MPI_COMM_WORLD, 0 );
187 #endif
188 
189  bool append_rank = false;
190  bool percent_rank_subst = false;
191  bool file_written = false;
192  int i, dim;
193  std::list< std::string >::iterator j;
194  bool dims[4] = { false, false, false, false };
195  const char* format = NULL; // output file format
196  std::list< std::string > in; // input file name list
197  std::string out; // output file name
198  bool verbose = false;
199  std::set< int > geom[4], mesh[4]; // user-specified IDs
200  std::vector< EntityHandle > set_list; // list of user-specified sets to write
201  std::vector< std::string > write_opts, read_opts;
202  std::string metis_partition_file;
203 #ifdef MOAB_HAVE_TEMPESTREMAP
204  std::string globalid_tag_name;
205  int spectral_order = 1;
206  bool unitscaling = false;
207 #endif
208 
209  const char* const mesh_tag_names[] = { DIRICHLET_SET_TAG_NAME, NEUMANN_SET_TAG_NAME, MATERIAL_SET_TAG_NAME,
211  const char* const geom_names[] = { "VERTEX", "CURVE", "SURFACE", "VOLUME" };
212 
213  // scan arguments
214  bool do_flag = true;
215  bool print_times = false;
216  bool generate[] = { false, false, false };
217  bool pval;
218  bool parallel = false, resolve_shared = false, exchange_ghosts = false;
219  for( i = 1; i < argc; i++ )
220  {
221  if( !argv[i][0] ) usage_error( argv[0] );
222 
223  if( do_flag && argv[i][0] == '-' )
224  {
225  if( !argv[i][1] || ( argv[i][1] != 'M' && argv[i][2] ) ) usage_error( argv[0] );
226 
227  switch( argv[i][1] )
228  {
229  // do flag arguments:
230  case '-':
231  do_flag = false;
232  break;
233  case 'g':
234  verbose = true;
235  break;
236  case 't':
237  print_times = true;
238  break;
239  case 'A':
240  break;
241  case 'h':
242  case 'H':
243  print_help( argv[0] );
244  break;
245  case 'l':
246  list_formats( gMB );
247  break;
248 #ifdef MOAB_HAVE_MPI
249  case 'P':
250  append_rank = true;
251  break;
252  case 'p':
253  percent_rank_subst = true;
254  break;
255  case 'M':
256  parallel = true;
257  if( argv[i][2] == '1' || argv[i][2] == '2' ) resolve_shared = true;
258  if( argv[i][2] == '2' ) exchange_ghosts = true;
259  break;
260 #endif
261 #ifdef MOAB_HAVE_TEMPESTREMAP
262  case 'B':
263  tempestin = true;
264  break;
265  case 'b':
266  tempestout = true;
267  break;
268  case 'S':
269  unitscaling = true;
270  break;
271 #endif
272  case '1':
273  case '2':
274  case '3':
275  dims[argv[i][1] - '0'] = true;
276  break;
277  // do options that require additional args:
278  default:
279  ++i;
280  if( i == argc || argv[i][0] == '-' )
281  {
282  std::cerr << "Expected argument following " << argv[i - 1] << std::endl;
283  usage_error( argv[0] );
284  }
285  if( argv[i - 1][1] == 'I' )
286  {
287  dim = atoi( argv[i] );
288  if( dim < 1 || dim > 2 )
289  {
290  std::cerr << "Invalid dimension value following -I" << std::endl;
291  usage_error( argv[0] );
292  }
293  generate[dim] = true;
294  continue;
295  }
296  pval = false;
297  switch( argv[i - 1][1] )
298  {
299  case 'a':
300  read_opts.push_back( std::string( "SAT_FILE=" ) + argv[i] );
301  pval = true;
302  break;
303  case 'f':
304  format = argv[i];
305  pval = true;
306  break;
307  case 'o':
308  write_opts.push_back( argv[i] );
309  pval = true;
310  break;
311  case 'O':
312  read_opts.push_back( argv[i] );
313  pval = true;
314  break;
315 #ifdef MOAB_HAVE_TEMPESTREMAP
316  case 'i':
317  globalid_tag_name = std::string( argv[i] );
318  pval = true;
319  break;
320  case 'r':
321  spectral_order = atoi( argv[i] );
322  pval = true;
323  break;
324 #endif
325  case 'v':
326  pval = parse_id_list( argv[i], geom[3] );
327  break;
328  case 's':
329  pval = parse_id_list( argv[i], geom[2] );
330  break;
331  case 'c':
332  pval = parse_id_list( argv[i], geom[1] );
333  break;
334  case 'V':
335  pval = parse_id_list( argv[i], geom[0] );
336  break;
337  case 'D':
338  pval = parse_id_list( argv[i], mesh[3] );
339  break;
340  case 'm':
341  pval = parse_id_list( argv[i], mesh[2] );
342  break;
343  case 'n':
344  pval = parse_id_list( argv[i], mesh[1] );
345  break;
346  case 'd':
347  pval = parse_id_list( argv[i], mesh[0] );
348  break;
349  case 'z':
350  metis_partition_file = argv[i];
351  pval = true;
352  break;
353  default:
354  std::cerr << "Invalid option: " << argv[i] << std::endl;
355  }
356 
357  if( !pval )
358  {
359  std::cerr << "Invalid flag or flag value: " << argv[i - 1] << " " << argv[i] << std::endl;
360  usage_error( argv[0] );
361  }
362  }
363  }
364  // do file names
365  else
366  {
367  in.push_back( argv[i] );
368  }
369  }
370  if( in.size() < 2 )
371  {
372  std::cerr << "No output file name specified." << std::endl;
373  usage_error( argv[0] );
374  }
375  // output file name is the last one specified
376  out = in.back();
377  in.pop_back();
378 
379  if( append_rank )
380  {
381  std::ostringstream mod;
382  mod << out << "." << proc_id;
383  out = mod.str();
384  }
385 
386  if( percent_rank_subst )
387  {
388  for( j = in.begin(); j != in.end(); ++j )
389  *j = percent_subst( *j, proc_id );
390  out = percent_subst( out, proc_id );
391  }
392 
393  // construct options string from individual options
394  std::string read_options, write_options;
395  if( parallel )
396  {
397  read_opts.push_back( "PARALLEL=READ_PART" );
398  read_opts.push_back( "PARTITION=PARALLEL_PARTITION" );
399  if( !append_rank && !percent_rank_subst ) write_opts.push_back( "PARALLEL=WRITE_PART" );
400  }
401  if( resolve_shared ) read_opts.push_back( "PARALLEL_RESOLVE_SHARED_ENTS" );
402  if( exchange_ghosts ) read_opts.push_back( "PARALLEL_GHOSTS=3.0.1" );
403 
404  if( !make_opts_string( read_opts, read_options ) || !make_opts_string( write_opts, write_options ) )
405  {
406 #ifdef MOAB_HAVE_MPI
407  MPI_Finalize();
408 #endif
409  return USAGE_ERROR;
410  }
411 
412  if( !metis_partition_file.empty() )
413  {
414  if( ( in.size() != 1 ) || ( proc_id != 0 ) )
415  {
416  std::cerr << " mpas partition allows only one input file, in serial conversion\n";
417 #ifdef MOAB_HAVE_MPI
418  MPI_Finalize();
419 #endif
420  return USAGE_ERROR;
421  }
422  }
423 
424  Tag id_tag = gMB->globalId_tag();
425 
426  // Read the input file.
427 #ifdef MOAB_HAVE_TEMPESTREMAP
428  if( tempestin && in.size() > 1 )
429  {
430  std::cerr << " we can read only one tempest files at a time\n";
431 #ifdef MOAB_HAVE_MPI
432  MPI_Finalize();
433 #endif
434  return USAGE_ERROR;
435  }
436  TempestRemapper* remapper = NULL;
437  if( tempestin or tempestout )
438  {
439 #ifdef MOAB_HAVE_MPI
440  remapper = new moab::TempestRemapper( gMB, pcomm, offlineGenerator );
441 #else
442  remapper = new moab::TempestRemapper( gMB, offlineGenerator );
443 #endif
444  }
445 
446  bool use_overlap_context = false;
447  Tag srcParentTag, tgtParentTag;
448 
449 #endif
450  // Allocate a single meshset that owns everything loaded across all
451  // input files. Writers that REQUIRE a designated file set (e.g.
452  // WriteNC and the new SCRIP/ESMF/Domain helpers, which call
453  // process_conventional_tags / synthesize a schema from one mesh
454  // root) need this set explicitly. Writers that don't care (h5m,
455  // vtk, ...) are unaffected — passing &file_set with the loaded
456  // entities is equivalent to passing nothing, since the same
457  // entities also live in the root set.
458  EntityHandle file_set = 0;
459  {
460  ErrorCode mrc = gMB->create_meshset( MESHSET_SET, file_set );
461  if( MB_SUCCESS != mrc )
462  {
463  std::cerr << "Failed to create file set." << std::endl;
464 #ifdef MOAB_HAVE_MPI
465  MPI_Finalize();
466 #endif
467  return OTHER_ERROR;
468  }
469  }
470  for( j = in.begin(); j != in.end(); ++j )
471  {
472  std::string inFileName = *j;
473 
474  reset_times();
475 
476 #ifdef MOAB_HAVE_TEMPESTREMAP
477  if( remapper )
478  {
479  remapper->meshValidate = false;
480  // remapper->constructEdgeMap = true;
481  remapper->initialize();
482 
483  if( tempestin )
484  {
486 
487  // convert
488  result = remapper->LoadMesh( moab::Remapper::SourceMesh, inFileName, moab::TempestRemapper::DEFAULT );
489  MB_CHK_ERR( result );
490 
491  Mesh* tempestMesh = remapper->GetMesh( moab::Remapper::SourceMesh );
492  tempestMesh->RemoveZeroEdges();
493  tempestMesh->RemoveCoincidentNodes();
494 
495  // Load the meshes and validate
496  result = remapper->ConvertTempestMesh( moab::Remapper::SourceMesh );
497 
498  if( unitscaling )
499  {
500  result = moab::IntxUtils::ScaleToRadius( gMB, srcmesh, 1.0 );
501  MB_CHK_ERR( result );
502  }
503 
504  // Check if we are converting a RLL grid
505  NcFile ncInput( inFileName.c_str(), NcFile::ReadOnly );
506 
507  NcError error_temp( NcError::silent_nonfatal );
508  // get the attribute
509  NcAtt* attRectilinear = ncInput.get_att( "rectilinear" );
510  NcVar* varGridDims = ncInput.get_var( "grid_dims" );
511 
512  // If rectilinear attribute present, mark it
513  std::vector< int > vecDimSizes( 3, 0 );
514  Tag rectilinearTag;
515  // Tag data contains: guessed mesh type, mesh size1, mesh size 2
516  // Example: CS(0)/ICO(1)/ICOD(2), num_elements, num_nodes
517  // : RLL(3), num_lat, num_lon
518  result = gMB->tag_get_handle( "ClimateMetadata", 3, MB_TYPE_INTEGER, rectilinearTag,
519  MB_TAG_SPARSE | MB_TAG_CREAT, vecDimSizes.data() );
520  MB_CHK_SET_ERR( result, "can't create rectilinear sizes tag" );
521 
522  if( attRectilinear != nullptr )
523  {
524  // Obtain rectilinear attributes (dimension sizes)
525  NcAtt* attRectilinearDim0Size = ncInput.get_att( "rectilinear_dim0_size" );
526  NcAtt* attRectilinearDim1Size = ncInput.get_att( "rectilinear_dim1_size" );
527 
528  if( attRectilinearDim0Size == nullptr )
529  {
530  _EXCEPTIONT( "Missing attribute \"rectilinear_dim0_size\"" );
531  }
532  if( attRectilinearDim1Size == nullptr )
533  {
534  _EXCEPTIONT( "Missing attribute \"rectilinear_dim1_size\"" );
535  }
536 
537  int nDim0Size = attRectilinearDim0Size->as_int( 0 );
538  int nDim1Size = attRectilinearDim1Size->as_int( 0 );
539 
540  // Obtain rectilinear attributes (dimension names)
541  NcAtt* attRectilinearDim0Name = ncInput.get_att( "rectilinear_dim0_name" );
542  NcAtt* attRectilinearDim1Name = ncInput.get_att( "rectilinear_dim1_name" );
543 
544  if( attRectilinearDim0Name == nullptr )
545  {
546  _EXCEPTIONT( "Missing attribute \"rectilinear_dim0_name\"" );
547  }
548  if( attRectilinearDim1Name == nullptr )
549  {
550  _EXCEPTIONT( "Missing attribute \"rectilinear_dim1_name\"" );
551  }
552 
553  std::string strDim0Name = attRectilinearDim0Name->as_string( 0 );
554  std::string strDim1Name = attRectilinearDim1Name->as_string( 0 );
555 
556  std::map< std::string, int > vecDimNameSizes;
557  // Push rectilinear attributes into array
558  vecDimNameSizes[strDim0Name] = nDim0Size;
559  vecDimNameSizes[strDim1Name] = nDim1Size;
560  vecDimSizes[0] = static_cast< int >( moab::TempestRemapper::RLL );
561  vecDimSizes[1] = vecDimNameSizes["lat"];
562  vecDimSizes[2] = vecDimNameSizes["lon"];
563  }
564  else if( varGridDims != nullptr )
565  {
566  // Obtain rectilinear attributes (dimension sizes)
567  NcDim* dimGridRank = varGridDims->get_dim( 0 );
568  if( dimGridRank == NULL )
569  {
570  _EXCEPTIONT( "Variable \"grid_dims\" has no dimensions" );
571  }
572 
573  int gridrank = dimGridRank->size();
574  // now get the rank dimensions
575  int gridsizes[2];
576  varGridDims->get( &( gridsizes[0] ), dimGridRank->size() );
577 
578  const Range& elems = remapper->GetMeshEntities( moab::Remapper::SourceMesh );
579  bool isQuads = elems.all_of_type( moab::MBQUAD );
580  bool isTris = elems.all_of_type( moab::MBTRI );
581 
582  if( gridrank == 1 )
583  {
584  vecDimSizes[0] = ( isQuads ? static_cast< int >( moab::TempestRemapper::CS )
585  : ( isTris ? static_cast< int >( moab::TempestRemapper::ICO )
586  : static_cast< int >( moab::TempestRemapper::ICOD ) ) );
587  vecDimSizes[1] = elems.size();
588  vecDimSizes[2] = remapper->GetMeshVertices( moab::Remapper::SourceMesh ).size();
589  }
590  else
591  {
592  vecDimSizes[0] = static_cast< int >( moab::TempestRemapper::RLL );
593  vecDimSizes[1] = gridsizes[0];
594  vecDimSizes[2] = gridsizes[1];
595  }
596  }
597  else
598  {
599  const Range& elems = remapper->GetMeshEntities( moab::Remapper::SourceMesh );
600  bool isQuads = elems.all_of_type( moab::MBQUAD );
601  bool isTris = elems.all_of_type( moab::MBTRI );
602  // vecDimSizes[0] = static_cast< int >( remapper->GetMeshType( moab::Remapper::SourceMesh );
603  vecDimSizes[0] = ( isQuads ? static_cast< int >( moab::TempestRemapper::CS )
604  : ( isTris ? static_cast< int >( moab::TempestRemapper::ICO )
605  : static_cast< int >( moab::TempestRemapper::ICOD ) ) );
606  vecDimSizes[1] = elems.size();
607  vecDimSizes[2] = remapper->GetMeshVertices( moab::Remapper::SourceMesh ).size();
608  }
609  moab::EntityHandle mSet = 0;
610  // mSet = remapper->GetMeshSet( moab::Remapper::SourceMesh );
611  result = gMB->tag_set_data( rectilinearTag, &mSet, 1, vecDimSizes.data() );
612  MB_CHK_ERR( result );
613 
614  switch( vecDimSizes[0] )
615  {
616  case 0:
617  printf( "Cubed-Sphere mesh: %d (elements), %d (vertices)\n", vecDimSizes[1], vecDimSizes[2] );
618  break;
619  case 1:
620  printf( "Rectilinear RLL mesh: (lon) %d X (lat) %d\n", vecDimSizes[2], vecDimSizes[1] );
621  break;
622  case 2:
623  printf( "Icosahedral (triangular) mesh: %d (elements), %d (vertices)\n", vecDimSizes[1],
624  vecDimSizes[2] );
625  break;
626  case 3:
627  default:
628  printf( "Polygonal mesh: %d (elements), %d (vertices)\n", vecDimSizes[1], vecDimSizes[2] );
629  break;
630  }
631 
632  ncInput.close();
633 
634  const size_t nOverlapFaces = tempestMesh->faces.size();
635  if( tempestMesh->vecSourceFaceIx.size() == nOverlapFaces &&
636  tempestMesh->vecSourceFaceIx.size() == nOverlapFaces )
637  {
638  int defaultInt = -1;
639  use_overlap_context = true;
640  // Check if our MOAB mesh has RED and BLUE tags; this would indicate we are
641  // converting an overlap grid
642  result = gMB->tag_get_handle( "TargetParent", 1, MB_TYPE_INTEGER, tgtParentTag,
643  MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );
644  MB_CHK_SET_ERR( result, "can't create target parent tag" );
645 
646  result = gMB->tag_get_handle( "SourceParent", 1, MB_TYPE_INTEGER, srcParentTag,
647  MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );
648  MB_CHK_SET_ERR( result, "can't create source parent tag" );
649 
650  const Range& faces = remapper->GetMeshEntities( moab::Remapper::SourceMesh );
651 
652  std::vector< int > gids( faces.size() ), srcpar( faces.size() ), tgtpar( faces.size() );
653  result = gMB->tag_get_data( id_tag, faces, &gids[0] );
654  MB_CHK_ERR( result );
655 
656  for( unsigned ii = 0; ii < faces.size(); ++ii )
657  {
658  srcpar[ii] = tempestMesh->vecSourceFaceIx[gids[ii] - 1];
659  tgtpar[ii] = tempestMesh->vecTargetFaceIx[gids[ii] - 1];
660  }
661 
662  result = gMB->tag_set_data( srcParentTag, faces, &srcpar[0] );
663  MB_CHK_ERR( result );
664  result = gMB->tag_set_data( tgtParentTag, faces, &tgtpar[0] );
665  MB_CHK_ERR( result );
666 
667  srcpar.clear();
668  tgtpar.clear();
669  gids.clear();
670  }
671  }
672  else if( tempestout )
673  {
676 
677  // load the mesh in MOAB format
678  std::vector< int > metadata( 2 );
679  result = remapper->LoadNativeMesh( *j, srcmesh, metadata );
680  MB_CHK_ERR( result );
681 
682  if( unitscaling )
683  {
684  result = moab::IntxUtils::ScaleToRadius( gMB, srcmesh, 1.0 );
685  MB_CHK_ERR( result );
686  }
687 
688  // Check if our MOAB mesh has RED and BLUE tags; this would indicate we are converting
689  // an overlap grid
690  ErrorCode rval1 = gMB->tag_get_handle( "SourceParent", srcParentTag );
691  ErrorCode rval2 = gMB->tag_get_handle( "TargetParent", tgtParentTag );
692  if( rval1 == MB_SUCCESS && rval2 == MB_SUCCESS )
693  {
694  use_overlap_context = true;
695  ovmesh = srcmesh;
696 
697  Tag countTag;
698  result = gMB->tag_get_handle( "Counting", countTag );
699  MB_CHK_ERR( result );
700 
701  // Load the meshes and validate
702  Tag order;
703  //ReorderTool reorder_tool( &core );
704  //result = reorder_tool.handle_order_from_int_tag( srcParentTag, -1, order );
705  //MB_CHK_ERR( result );
706  //result = reorder_tool.reorder_entities( order );
707  //MB_CHK_ERR( result );
708  //result = gMB->tag_delete( order );
709  //MB_CHK_ERR( result );
711  MB_CHK_ERR( result );
712  }
713  else
714  {
715  if( metadata[0] == static_cast< int >( moab::TempestRemapper::RLL ) )
716  {
717  assert( metadata.size() );
718  std::cout << "Converting a RLL mesh with rectilinear dimension: " << metadata[0] << " X "
719  << metadata[1] << std::endl;
720  }
721 
722  // Convert the mesh and validate
723  result = remapper->ConvertMeshToTempest( moab::Remapper::SourceMesh );
724  MB_CHK_ERR( result );
725  }
726  }
727  }
728  else
729  result = gMB->load_file( j->c_str(), &file_set, read_options.c_str() );
730 #else
731  result = gMB->load_file( j->c_str(), &file_set, read_options.c_str() );
732 #endif
733  if( MB_SUCCESS != result )
734  {
735  std::cerr << "Failed to load \"" << *j << "\"." << std::endl;
736  std::cerr << "Error code: " << gMB->get_error_string( result ) << " (" << result << ")" << std::endl;
737  std::string message;
738  if( MB_SUCCESS == gMB->get_last_error( message ) && !message.empty() )
739  std::cerr << "Error message: " << message << std::endl;
740 #ifdef MOAB_HAVE_MPI
741  MPI_Finalize();
742 #endif
743  return READ_ERROR;
744  }
745  if( !proc_id ) std::cerr << "Read \"" << *j << "\"" << std::endl;
746  if( print_times && !proc_id ) write_times( std::cout );
747  }
748 
749  // Determine if the user has specified any geometry sets to write
750  bool have_geom = false;
751  for( dim = 0; dim <= 3; ++dim )
752  {
753  if( !geom[dim].empty() ) have_geom = true;
754  if( verbose ) print_id_list( geom_names[dim], std::cout, geom[dim] );
755  }
756 
757  // True if the user has specified any sets to write
758  bool have_sets = have_geom;
759 
760  // Get geometry tags
761  Tag dim_tag;
762  if( have_geom )
763  {
764  if( id_tag == 0 )
765  {
766  std::cerr << "No ID tag defined." << std::endl;
767  have_geom = false;
768  }
769  result = gMB->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, dim_tag );
770  if( MB_SUCCESS != result )
771  {
772  std::cerr << "No geometry tag defined." << std::endl;
773  have_geom = false;
774  }
775  }
776 
777  // Get geometry sets
778  if( have_geom )
779  {
780  int id_val;
781  Tag tags[] = { id_tag, dim_tag };
782  const void* vals[] = { &id_val, &dim };
783  for( dim = 0; dim <= 3; ++dim )
784  {
785  int init_count = set_list.size();
786  for( std::set< int >::iterator iter = geom[dim].begin(); iter != geom[dim].end(); ++iter )
787  {
788  id_val = *iter;
789  range.clear();
790  result = gMB->get_entities_by_type_and_tag( 0, MBENTITYSET, tags, vals, 2, range );
791  if( MB_SUCCESS != result || range.empty() )
792  {
793  range.clear();
794  std::cerr << geom_names[dim] << " " << id_val << " not found.\n";
795  }
796  std::copy( range.begin(), range.end(), std::back_inserter( set_list ) );
797  }
798 
799  if( verbose )
800  std::cout << "Found " << ( set_list.size() - init_count ) << ' ' << geom_names[dim] << " sets"
801  << std::endl;
802  }
803  }
804 
805  // Get mesh groupings
806  for( i = 0; i < 4; ++i )
807  {
808  if( verbose ) print_id_list( mesh_tag_names[i], std::cout, mesh[i] );
809 
810  if( mesh[i].empty() ) continue;
811  have_sets = true;
812 
813  // Get tag
814  Tag tag;
815  result = gMB->tag_get_handle( mesh_tag_names[i], 1, MB_TYPE_INTEGER, tag );
816  if( MB_SUCCESS != result )
817  {
818  std::cerr << "Tag not found: " << mesh_tag_names[i] << std::endl;
819  continue;
820  }
821 
822  // get entity sets
823  int init_count = set_list.size();
824  for( std::set< int >::iterator iter = mesh[i].begin(); iter != mesh[i].end(); ++iter )
825  {
826  range.clear();
827  const void* vals[] = { &*iter };
828  result = gMB->get_entities_by_type_and_tag( 0, MBENTITYSET, &tag, vals, 1, range );
829  if( MB_SUCCESS != result || range.empty() )
830  {
831  range.clear();
832  std::cerr << mesh_tag_names[i] << " " << *iter << " not found.\n";
833  }
834  std::copy( range.begin(), range.end(), std::back_inserter( set_list ) );
835  }
836 
837  if( verbose )
838  std::cout << "Found " << ( set_list.size() - init_count ) << ' ' << mesh_tag_names[i] << " sets"
839  << std::endl;
840  }
841 
842  // Check if output is limited to certain dimensions of elements
843  bool bydim = false;
844  for( dim = 1; dim < 4; ++dim )
845  if( dims[dim] ) bydim = true;
846 
847  // Check conflicting input
848  if( bydim )
849  {
850  if( generate[1] && !dims[1] )
851  {
852  std::cerr << "Warning: Request to generate 1D internal entities but not export them." << std::endl;
853  generate[1] = false;
854  }
855  if( generate[2] && !dims[2] )
856  {
857  std::cerr << "Warning: Request to generate 2D internal entities but not export them." << std::endl;
858  generate[2] = false;
859  }
860  }
861 
862  // Generate any internal entities
863  if( generate[1] || generate[2] )
864  {
865  EntityHandle all_mesh = 0;
866  const EntityHandle* sets = &all_mesh;
867  int num_sets = 1;
868  if( have_sets )
869  {
870  num_sets = set_list.size();
871  sets = &set_list[0];
872  }
873  for( i = 0; i < num_sets; ++i )
874  {
875  Range dim3, dim2, adj;
876  gMB->get_entities_by_dimension( sets[i], 3, dim3, true );
877  if( generate[1] )
878  {
879  gMB->get_entities_by_dimension( sets[i], 2, dim2, true );
880  gMB->get_adjacencies( dim3, 1, true, adj, Interface::UNION );
881  gMB->get_adjacencies( dim2, 1, true, adj, Interface::UNION );
882  }
883  if( generate[2] )
884  {
885  gMB->get_adjacencies( dim3, 2, true, adj, Interface::UNION );
886  }
887  if( sets[i] ) gMB->add_entities( sets[i], adj );
888  }
889  }
890 
891  // Delete any entities not of the dimensions to be exported
892  if( bydim )
893  {
894  // Get list of dead elements
895  Range dead_entities, tmp_range;
896  for( dim = 1; dim <= 3; ++dim )
897  {
898  if( dims[dim] ) continue;
899  gMB->get_entities_by_dimension( 0, dim, tmp_range );
900  dead_entities.merge( tmp_range );
901  }
902  // Remove dead entities from all sets, and add all
903  // empty sets to list of dead entities.
904  Range empty_sets;
905  remove_entities_from_sets( gMB, dead_entities, empty_sets );
906  while( !empty_sets.empty() )
907  {
908  if( !set_list.empty() ) remove_from_vector( set_list, empty_sets );
909  dead_entities.merge( empty_sets );
910  tmp_range.clear();
911  remove_entities_from_sets( gMB, empty_sets, tmp_range );
912  empty_sets = subtract( tmp_range, dead_entities );
913  }
914  // Destroy dead entities
915  gMB->delete_entities( dead_entities );
916  }
917 
918  // If user specified sets to write, but none were found, exit.
919  if( have_sets && set_list.empty() )
920  {
921  std::cerr << "Nothing to write." << std::endl;
922 #ifdef MOAB_HAVE_MPI
923  MPI_Finalize();
924 #endif
925  return ENT_NOT_FOUND;
926  }
927 
928  // interpret the mpas partition file created by gpmetis
929  if( !metis_partition_file.empty() )
930  {
931  int err = process_partition_file( gMB, metis_partition_file );
932  if( err )
933  {
934  std::cerr << "Failed to process partition file \"" << metis_partition_file << "\"." << std::endl;
935 #ifdef MOAB_HAVE_MPI
936  MPI_Finalize();
937 #endif
938  return WRITE_ERROR;
939  }
940  }
941  if( verbose )
942  {
943  if( have_sets )
944  std::cout << "Found " << set_list.size() << " specified sets to write (total)." << std::endl;
945  else
946  std::cout << "No sets specifed. Writing entire mesh." << std::endl;
947  }
948 
949  // Write the output file
950  reset_times();
951 #ifdef MOAB_HAVE_TEMPESTREMAP
952  if( remapper )
953  {
954  Range faces;
955  Mesh* tempestMesh =
956  remapper->GetMesh( ( use_overlap_context ? moab::Remapper::OverlapMesh : moab::Remapper::SourceMesh ) );
957  moab::EntityHandle& srcmesh =
958  remapper->GetMeshSet( ( use_overlap_context ? moab::Remapper::OverlapMesh : moab::Remapper::SourceMesh ) );
959  result = gMB->get_entities_by_dimension( srcmesh, 2, faces );
960  MB_CHK_ERR( result );
961  int ntot_elements = 0, nelements = faces.size();
962 #ifdef MOAB_HAVE_MPI
963  int ierr = MPI_Allreduce( &nelements, &ntot_elements, 1, MPI_INT, MPI_SUM, pcomm->comm() );
964  if( ierr != 0 ) MB_CHK_SET_ERR( MB_FAILURE, "MPI_Allreduce failed to get total source elements" );
965 #else
966  ntot_elements = nelements;
967 #endif
968 
969  Tag gidTag = gMB->globalId_tag();
970  std::vector< int > gids( faces.size() );
971  result = gMB->tag_get_data( gidTag, faces, &gids[0] );
972  MB_CHK_ERR( result );
973 
974  if( faces.size() > 1 && gids[0] == gids[1] && !use_overlap_context )
975  {
976 #ifdef MOAB_HAVE_MPI
977  result = pcomm->assign_global_ids( srcmesh, 2, 1, false );
978  MB_CHK_ERR( result );
979 #else
980  result = remapper->assign_vertex_element_IDs( gidTag, srcmesh, 2, 1 );
981  MB_CHK_ERR( result );
982  result = remapper->assign_vertex_element_IDs( gidTag, srcmesh, 0, 1 );
983  MB_CHK_ERR( result );
984 #endif
985  }
986 
987  // VSM: If user requested explicitly for some metadata, we need to generate the DoF ID tag
988  // and set the appropriate numbering based on specified discretization order
989  // Useful only for SE meshes with GLL DoFs
990  if( spectral_order > 1 && globalid_tag_name.size() > 1 )
991  {
992  // Generate continuous (CGLL) DoF numbering: shared nodes at element boundaries
993  // get the same global DoF ID. Tag name is user-specified (typically "GLOBAL_DOFS").
994  result = remapper->GenerateMeshMetadata( *tempestMesh, ntot_elements, faces, NULL, globalid_tag_name,
995  spectral_order );
996  MB_CHK_ERR( result );
997 
998  // Generate discontinuous (DGLL) DoF numbering: each element owns nP*nP
999  // independent DoFs, numbered sequentially across elements.
1000  // Tag name: "D" + user-specified name (e.g., "DGLOBAL_DOFS").
1001  {
1002  const int nP = spectral_order;
1003  const int dofsPerElem = nP * nP;
1004  const std::string dTagName = "D" + globalid_tag_name;
1005 
1006  Tag dgllTag;
1007  result = gMB->tag_get_handle( dTagName.c_str(), dofsPerElem, MB_TYPE_INTEGER, dgllTag,
1009  MB_CHK_ERR( result );
1010 
1011  // Assign sequential DoF IDs: element k gets [k*nP*nP+1, (k+1)*nP*nP]
1012  // Use GLOBAL_ID ordering to ensure consistent numbering across processes
1013  Tag gidTag = gMB->globalId_tag();
1014  std::vector< int > elemGids( faces.size() );
1015  result = gMB->tag_get_data( gidTag, faces, elemGids.data() );
1016  MB_CHK_ERR( result );
1017 
1018  std::vector< int > dofIDs( dofsPerElem );
1019  for( size_t ie = 0; ie < faces.size(); ++ie )
1020  {
1021  // Use 0-based element index from GLOBAL_ID (1-based) for DOF numbering
1022  const int elemIdx = elemGids[ie] - 1;
1023  for( int j = 0; j < nP; ++j )
1024  for( int i = 0; i < nP; ++i )
1025  dofIDs[j * nP + i] = elemIdx * dofsPerElem + j * nP + i + 1;
1026 
1027  EntityHandle eh = faces[ie];
1028  result = gMB->tag_set_data( dgllTag, &eh, 1, dofIDs.data() );
1029  MB_CHK_ERR( result );
1030  }
1031 
1032  if( !proc_id )
1033  std::cout << "Generated discontinuous DoF tag \"" << dTagName << "\" with " << dofsPerElem
1034  << " DoFs/element (" << ntot_elements * dofsPerElem << " total)\n";
1035  }
1036  }
1037 
1038  if( tempestout )
1039  {
1040  // Check if our MOAB mesh has RED and BLUE tags; this would indicate we are converting an
1041  // overlap grid
1042  if( use_overlap_context && false )
1043  {
1044  const int nOverlapFaces = faces.size();
1045  // Overlap mesh: resize the source and target connection arrays
1046  tempestMesh->vecSourceFaceIx.resize( nOverlapFaces ); // 0-based indices corresponding to source mesh
1047  tempestMesh->vecTargetFaceIx.resize( nOverlapFaces ); // 0-based indices corresponding to target mesh
1048  result = gMB->tag_get_data( srcParentTag, faces, &tempestMesh->vecSourceFaceIx[0] );
1049  MB_CHK_ERR( result );
1050  result = gMB->tag_get_data( tgtParentTag, faces, &tempestMesh->vecTargetFaceIx[0] );
1051  MB_CHK_ERR( result );
1052  }
1053  // Write out the mesh using TempestRemap
1054  tempestMesh->Write( out, NcFile::Netcdf4 );
1055  file_written = true;
1056  }
1057  delete remapper; // cleanup
1058  }
1059 #endif
1060 
1061  if( !file_written )
1062  {
1063  if( have_sets )
1064  result = gMB->write_file( out.c_str(), format, write_options.c_str(), &set_list[0], set_list.size() );
1065  else
1066  // Pass the tracked file_set explicitly. Required by writers
1067  // that need exactly one designated set (WriteNC + the
1068  // SCRIP/ESMF/Domain helpers); semantically a no-op for the
1069  // generic writers that previously took the no-set form.
1070  result = gMB->write_file( out.c_str(), format, write_options.c_str(), &file_set, 1 );
1071  if( MB_SUCCESS != result )
1072  {
1073  std::cerr << "Failed to write \"" << out << "\"." << std::endl;
1074  std::cerr << "Error code: " << gMB->get_error_string( result ) << " (" << result << ")" << std::endl;
1075  std::string message;
1076  if( MB_SUCCESS == gMB->get_last_error( message ) && !message.empty() )
1077  std::cerr << "Error message: " << message << std::endl;
1078 #ifdef MOAB_HAVE_MPI
1079  MPI_Finalize();
1080 #endif
1081  return WRITE_ERROR;
1082  }
1083  }
1084 
1085  if( !proc_id ) std::cerr << "Wrote \"" << out << "\"" << std::endl;
1086  if( print_times && !proc_id ) write_times( std::cout );
1087 
1088 #ifdef MOAB_HAVE_MPI
1089  MPI_Finalize();
1090 #endif
1091  return 0;
1092 }

References moab::Interface::add_entities(), moab::Range::all_of_type(), moab::ParallelComm::assign_global_ids(), moab::TempestRemapper::assign_vertex_element_IDs(), moab::Range::begin(), moab::Range::clear(), moab::ParallelComm::comm(), moab::TempestRemapper::ConvertMeshToTempest(), moab::TempestRemapper::ConvertTempestMesh(), moab::Interface::create_meshset(), moab::TempestRemapper::CS, moab::TempestRemapper::DEFAULT, moab::Interface::delete_entities(), DIRICHLET_SET_TAG_NAME, moab::Range::empty(), moab::Range::end(), ENT_NOT_FOUND, ErrorCode, moab::TempestRemapper::GenerateMeshMetadata(), GEOM_DIMENSION_TAG_NAME, moab::Interface::get_adjacencies(), moab::Interface::get_entities_by_dimension(), moab::Interface::get_entities_by_type_and_tag(), moab::Interface::get_error_string(), moab::Interface::get_last_error(), moab::TempestRemapper::GetMesh(), moab::TempestRemapper::GetMeshEntities(), moab::TempestRemapper::GetMeshSet(), moab::TempestRemapper::GetMeshVertices(), moab::Interface::globalId_tag(), gMB, moab::TempestRemapper::ICO, moab::TempestRemapper::ICOD, moab::TempestRemapper::initialize(), list_formats(), moab::Interface::load_file(), moab::TempestRemapper::LoadMesh(), moab::Remapper::LoadNativeMesh(), make_opts_string(), MATERIAL_SET_TAG_NAME, MB_CHK_ERR, MB_CHK_SET_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TAG_SPARSE, MB_TYPE_INTEGER, MBENTITYSET, MBQUAD, MBTRI, moab::Range::merge(), MESHSET_SET, moab::TempestRemapper::meshValidate, NEUMANN_SET_TAG_NAME, OTHER_ERROR, moab::Remapper::OverlapMesh, PARALLEL_PARTITION_TAG_NAME, parse_id_list(), percent_subst(), print_help(), print_id_list(), process_partition_file(), READ_ERROR, remove_entities_from_sets(), moab::remove_from_vector(), reset_times(), moab::TempestRemapper::RLL, moab::IntxUtils::ScaleToRadius(), moab::Range::size(), moab::Remapper::SourceMesh, moab::subtract(), moab::Interface::tag_get_data(), moab::Interface::tag_get_handle(), moab::Interface::tag_set_data(), moab::Interface::UNION, USAGE_ERROR, usage_error(), verbose, WRITE_ERROR, moab::Interface::write_file(), and write_times().

◆ make_opts_string()

bool make_opts_string ( std::vector< std::string >  options,
std::string &  result 
)
static

Definition at line 1237 of file convert.cpp.

1238 {
1239  opts.clear();
1240  if( options.empty() ) return true;
1241 
1242  // choose a separator character
1243  std::vector< std::string >::const_iterator i;
1244  char separator = '\0';
1245  const char* alt_separators = ";+,:\t\n";
1246  for( const char* sep_ptr = alt_separators; *sep_ptr; ++sep_ptr )
1247  {
1248  bool seen = false;
1249  for( i = options.begin(); i != options.end(); ++i )
1250  if( i->find( *sep_ptr, 0 ) != std::string::npos )
1251  {
1252  seen = true;
1253  break;
1254  }
1255  if( !seen )
1256  {
1257  separator = *sep_ptr;
1258  break;
1259  }
1260  }
1261  if( !separator )
1262  {
1263  std::cerr << "Error: cannot find separator character for options string" << std::endl;
1264  return false;
1265  }
1266  if( separator != ';' )
1267  {
1268  opts = ";";
1269  opts += separator;
1270  }
1271 
1272  // concatenate options
1273  i = options.begin();
1274  opts += *i;
1275  for( ++i; i != options.end(); ++i )
1276  {
1277  opts += separator;
1278  opts += *i;
1279  }
1280 
1281  return true;
1282 }

Referenced by main().

◆ parse_id_list()

bool parse_id_list ( const char *  string,
std::set< int > &  results 
)
static

Definition at line 1094 of file convert.cpp.

1095 {
1096  bool okay = true;
1097  char* mystr = strdup( string );
1098  for( const char* ptr = strtok( mystr, "," ); ptr; ptr = strtok( 0, "," ) )
1099  {
1100  char* endptr;
1101  long val = strtol( ptr, &endptr, 0 );
1102  if( endptr == ptr || val <= 0 )
1103  {
1104  std::cerr << "Not a valid id: " << ptr << std::endl;
1105  okay = false;
1106  break;
1107  }
1108 
1109  long val2 = val;
1110  if( *endptr == '-' )
1111  {
1112  const char* sptr = endptr + 1;
1113  val2 = strtol( sptr, &endptr, 0 );
1114  if( endptr == sptr || val2 <= 0 )
1115  {
1116  std::cerr << "Not a valid id: " << sptr << std::endl;
1117  okay = false;
1118  break;
1119  }
1120  if( val2 < val )
1121  {
1122  std::cerr << "Invalid id range: " << ptr << std::endl;
1123  okay = false;
1124  break;
1125  }
1126  }
1127 
1128  if( *endptr )
1129  {
1130  std::cerr << "Unexpected character: " << *endptr << std::endl;
1131  okay = false;
1132  break;
1133  }
1134 
1135  for( ; val <= val2; ++val )
1136  if( !results.insert( (int)val ).second ) std::cerr << "Warning: duplicate Id: " << val << std::endl;
1137  }
1138 
1139  free( mystr );
1140  return okay;
1141 }

Referenced by main().

◆ percent_subst()

std::string percent_subst ( const std::string &  s,
int  val 
)
static

Definition at line 1355 of file convert.cpp.

1356 {
1357  if( s.empty() ) return s;
1358 
1359  size_t j = s.find( '%' );
1360  if( j == std::string::npos ) return s;
1361 
1362  std::ostringstream st;
1363  st << s.substr( 0, j );
1364  st << val;
1365 
1366  size_t i;
1367  while( ( i = s.find( '%', j + 1 ) ) != std::string::npos )
1368  {
1369  st << s.substr( j, i - j );
1370  st << val;
1371  j = i;
1372  }
1373  st << s.substr( j + 1 );
1374  return st.str();
1375 }

Referenced by main().

◆ print_help()

static void print_help ( const char *  name)
static

Definition at line 128 of file convert.cpp.

129 {
130  std::cout << " This program can be used to convert between mesh file\n"
131  " formats, extract a subset of a mesh file to a separate\n"
132  " file, or both. The type of file to write is determined\n"
133  " from the file extension (e.g. \".vtk\") portion of the\n"
134  " output file name.\n"
135  " \n"
136  " While MOAB strives to export and import all data from\n"
137  " each supported file format, most file formats do\n"
138  " not support MOAB's entire data model. Thus MOAB cannot\n"
139  " guarantee lossless conversion for any file formats\n"
140  " other than the native HDF5 representation.\n"
141  "\n";
142 
143  print_usage( name, std::cout );
144  exit( 0 );
145 }

References print_usage().

Referenced by main().

◆ print_id_list()

void print_id_list ( const char *  head,
std::ostream &  stream,
const std::set< int > &  list 
)
static

Definition at line 1143 of file convert.cpp.

1144 {
1145  stream << head << ": ";
1146 
1147  if( list.empty() )
1148  {
1149  stream << "(none)" << std::endl;
1150  return;
1151  }
1152 
1153  int start, prev;
1154  std::set< int >::const_iterator iter = list.begin();
1155  start = prev = *( iter++ );
1156  for( ;; )
1157  {
1158  if( iter == list.end() || *iter != 1 + prev )
1159  {
1160  stream << start;
1161  if( prev != start ) stream << '-' << prev;
1162  if( iter == list.end() ) break;
1163  stream << ", ";
1164  start = *iter;
1165  }
1166  prev = *( iter++ );
1167  }
1168 
1169  stream << std::endl;
1170 }

Referenced by main().

◆ print_time()

static void print_time ( int  clk_per_sec,
const char *  prefix,
clock_t  ticks,
std::ostream &  stream 
)
static

Definition at line 1172 of file convert.cpp.

1173 {
1174  ticks *= clk_per_sec / 100;
1175  clock_t centi = ticks % 100;
1176  clock_t seconds = ticks / 100;
1177  stream << prefix;
1178  if( seconds < 120 )
1179  {
1180  stream << ( ticks / 100 ) << "." << centi << "s" << std::endl;
1181  }
1182  else
1183  {
1184  clock_t minutes = ( seconds / 60 ) % 60;
1185  clock_t hours = ( seconds / 3600 );
1186  seconds %= 60;
1187  if( hours ) stream << hours << "h";
1188  if( minutes ) stream << minutes << "m";
1189  if( seconds || centi ) stream << seconds << "." << centi << "s";
1190  stream << " (" << ( ticks / 100 ) << "." << centi << "s)" << std::endl;
1191  }
1192 }

Referenced by main(), MetisPartitioner::partition_mesh(), ZoltanPartitioner::partition_mesh(), MetisPartitioner::partition_mesh_and_geometry(), ZoltanPartitioner::partition_mesh_and_geometry(), and write_times().

◆ print_usage()

static void print_usage ( const char *  name,
std::ostream &  stream 
)
static

Definition at line 61 of file convert.cpp.

62 {
63  stream << "Usage: " << name
64  << " [-a <sat_file>|-A] [-t] [subset options] [-f format] <input_file> [<input_file2> "
65  "...] <output_file>"
66  << std::endl
67  << "\t-f <format> - Specify output file format" << std::endl
68  << "\t-a <acis_file> - ACIS SAT file dumped by .cub reader (same as \"-o "
69  "SAT_FILE=acis_file\""
70  << std::endl
71  << "\t-A - .cub file reader should not dump a SAT file (depricated default)" << std::endl
72  << "\t-o option - Specify write option. Repeat for multiple options." << std::endl
73  << "\t Common write options:" << std::endl
74  << "\t WRITE_FORMAT={SCRIP|ESMF|DOMAIN}" << std::endl
75  << "\t Force NetCDF output into a specific grid layout" << std::endl
76  << "\t (overrides the source mesh's __MESH_TYPE tag)." << std::endl
77  << "\t Example: -o WRITE_FORMAT=SCRIP in.nc out_scrip.nc" << std::endl
78  << "\t PARALLEL=WRITE_PART (auto-set under -M)" << std::endl
79  << "\t See README.IO for the full list of writer-specific options." << std::endl
80  << "\t-O option - Specify read option. Repeat for multiple options." << std::endl
81  << "\t See README.IO for the full list of reader-specific options." << std::endl
82  << "\t-t - Time read and write of files." << std::endl
83  << "\t-g - Enable verbose/debug output." << std::endl
84  << "\t-h - Print this help text and exit." << std::endl
85  << "\t-l - List available file formats and exit." << std::endl
86  << "\t-I dim - Generate internal entities of specified dimension." << std::endl
87 #ifdef MOAB_HAVE_MPI
88  << "\t-P - Append processor ID to output file name" << std::endl
89  << "\t-p - Replace '%' with processor ID in input and output file name" << std::endl
90  << "\t-M[0|1|2] - Read/write in parallel, optionally also doing "
91  "resolve_shared_ents (1) and exchange_ghosts (2)"
92  << std::endl
93  << "\t-z <file> - Read metis partition information corresponding to an MPAS grid "
94  "file and create h5m partition file"
95  << std::endl
96 #endif
97 
98 #ifdef MOAB_HAVE_TEMPESTREMAP
99  << "\t-B - Use TempestRemap exodus file reader and convert to MOAB format" << std::endl
100  << "\t-b - Convert MOAB mesh to TempestRemap exodus file writer" << std::endl
101  << "\t-S - Scale climate mesh to unit sphere" << std::endl
102  << "\t-i - Name of the global DoF tag to use with mbtempest" << std::endl
103  << "\t-r - Order of field DoF (discretization) data; FV=1,SE=[1,N]" << std::endl
104 #endif
105  << "\t-- - treat all subsequent options as file names" << std::endl
106  << "\t (allows file names beginning with '-')" << std::endl
107  << " subset options: " << std::endl
108  << "\tEach of the following options should be followed by " << std::endl
109  << "\ta list of ids. IDs may be separated with commas. " << std::endl
110  << "\tRanges of IDs may be specified with a '-' between " << std::endl
111  << "\ttwo values. The list may not contain spaces." << std::endl
112  << "\t-v - Volume" << std::endl
113  << "\t-s - Surface" << std::endl
114  << "\t-c - Curve" << std::endl
115  << "\t-V - Vertex" << std::endl
116  << "\t-m - Material set (block)" << std::endl
117  << "\t-d - Dirichlet set (nodeset)" << std::endl
118  << "\t-n - Neumann set (sideset)" << std::endl
119  << "\t-D - Parallel partitioning set (PARALLEL_PARTITION)" << std::endl
120  << "\tThe presence of one or more of the following flags limits " << std::endl
121  << "\tthe exported mesh to only elements of the corresponding " << std::endl
122  << "\tdimension. Vertices are always exported." << std::endl
123  << "\t-1 - Edges " << std::endl
124  << "\t-2 - Tri, Quad, Polygon " << std::endl
125  << "\t-3 - Tet, Hex, Prism, etc. " << std::endl;
126 }

Referenced by print_help(), and usage_error().

◆ process_partition_file()

int process_partition_file ( Interface gMB,
std::string &  metis_partition_file 
)
static

Definition at line 1377 of file convert.cpp.

1378 {
1379  // how many faces in the file ? how do we make sure it is an mpas file?
1380  // mpas atmosphere files can be downloaded from here
1381  // https://mpas-dev.github.io/atmosphere/atmosphere_meshes.html
1382  Range faces;
1383  MB_CHK_ERR( mb->get_entities_by_dimension( 0, 2, faces ) );
1384  std::cout << " MPAS model has " << faces.size() << " polygons\n";
1385 
1386  // read the partition file
1387  std::ifstream partfile;
1388  partfile.open( metis_partition_file.c_str() );
1389  std::string line;
1390  std::vector< int > parts;
1391  parts.resize( faces.size(), -1 );
1392  int i = 0;
1393  if( partfile.is_open() )
1394  {
1395  while( getline( partfile, line ) )
1396  {
1397  // cout << line << '\n';
1398  parts[i++] = atoi( line.c_str() );
1399  if( i > (int)faces.size() )
1400  {
1401  std::cerr << " too many lines in partition file \n. bail out \n";
1402  return 1;
1403  }
1404  }
1405  partfile.close();
1406  }
1407  std::vector< int >::iterator pmax = max_element( parts.begin(), parts.end() );
1408  std::vector< int >::iterator pmin = min_element( parts.begin(), parts.end() );
1409  if( *pmin <= -1 )
1410  {
1411  std::cerr << " partition file is incomplete, *pmin is -1 !! \n";
1412  return 1;
1413  }
1414  std::cout << " partitions range: " << *pmin << " " << *pmax << "\n";
1415  Tag part_set_tag;
1416  int dum_id = -1;
1417  MB_CHK_ERR( mb->tag_get_handle( "PARALLEL_PARTITION", 1, MB_TYPE_INTEGER, part_set_tag,
1418  MB_TAG_SPARSE | MB_TAG_CREAT, &dum_id ) );
1419 
1420  // get any sets already with this tag, and clear them
1421  // remove the parallel partition sets if they exist
1422  Range tagged_sets;
1423  MB_CHK_ERR(
1424  mb->get_entities_by_type_and_tag( 0, MBENTITYSET, &part_set_tag, NULL, 1, tagged_sets, Interface::UNION ) );
1425  if( !tagged_sets.empty() )
1426  {
1427  MB_CHK_ERR( mb->clear_meshset( tagged_sets ) );
1428  MB_CHK_ERR( mb->tag_delete_data( part_set_tag, tagged_sets ) );
1429  }
1430  Tag gid;
1431  MB_CHK_ERR( mb->tag_get_handle( "GLOBAL_ID", gid ) );
1432  int num_sets = *pmax + 1;
1433  if( *pmin != 0 )
1434  {
1435  std::cout << " problem reading parts; min is not 0 \n";
1436  return 1;
1437  }
1438  for( i = 0; i < num_sets; i++ )
1439  {
1440  EntityHandle new_set;
1441  MB_CHK_ERR( mb->create_meshset( MESHSET_SET, new_set ) );
1442  tagged_sets.insert( new_set );
1443  }
1444  int* dum_ids = new int[num_sets];
1445  for( i = 0; i < num_sets; i++ )
1446  dum_ids[i] = i;
1447 
1448  MB_CHK_ERR( mb->tag_set_data( part_set_tag, tagged_sets, dum_ids ) );
1449  delete[] dum_ids;
1450 
1451  std::vector< int > gids;
1452  int num_faces = (int)faces.size();
1453  gids.resize( num_faces );
1454  MB_CHK_ERR( mb->tag_get_data( gid, faces, &gids[0] ) );
1455 
1456  for( int j = 0; j < num_faces; j++ )
1457  {
1458  int eid = gids[j];
1459  EntityHandle eh = faces[j];
1460  int partition = parts[eid - 1];
1461  if( partition < 0 || partition >= num_sets )
1462  {
1463  std::cout << " wrong partition number \n";
1464  return 1;
1465  }
1466  MB_CHK_ERR( mb->add_entities( tagged_sets[partition], &eh, 1 ) );
1467  }
1468  return 0;
1469 }

References moab::Core::add_entities(), moab::Core::clear_meshset(), moab::Core::create_meshset(), moab::Range::empty(), moab::Core::get_entities_by_dimension(), moab::Core::get_entities_by_type_and_tag(), moab::Range::insert(), mb, MB_CHK_ERR, MB_TAG_CREAT, MB_TAG_SPARSE, MB_TYPE_INTEGER, MBENTITYSET, MESHSET_SET, moab::Range::size(), moab::Core::tag_delete_data(), moab::Core::tag_get_data(), moab::Core::tag_get_handle(), moab::Core::tag_set_data(), and moab::Interface::UNION.

Referenced by main().

◆ remove_entities_from_sets()

void remove_entities_from_sets ( Interface gMB,
Range dead_entities,
Range empty_sets 
)
static

Definition at line 1327 of file convert.cpp.

1328 {
1329  empty_sets.clear();
1330  Range sets;
1331  gMB->get_entities_by_type( 0, MBENTITYSET, sets );
1332  for( Range::iterator i = sets.begin(); i != sets.end(); ++i )
1333  {
1334  Range set_contents;
1335  gMB->get_entities_by_handle( *i, set_contents, false );
1336  set_contents = intersect( set_contents, dead_entities );
1337  gMB->remove_entities( *i, set_contents );
1338  set_contents.clear();
1339  gMB->get_entities_by_handle( *i, set_contents, false );
1340  if( set_contents.empty() ) empty_sets.insert( *i );
1341  }
1342 }

References moab::Range::begin(), moab::Range::clear(), moab::Range::empty(), moab::Range::end(), moab::Interface::get_entities_by_handle(), moab::Interface::get_entities_by_type(), gMB, moab::Range::insert(), moab::intersect(), MBENTITYSET, and moab::Interface::remove_entities().

Referenced by main().

◆ remove_from_vector()

void remove_from_vector ( std::vector< EntityHandle > &  vect,
const Range ents_to_remove 
)
static

Definition at line 1344 of file convert.cpp.

1345 {
1347  std::vector< EntityHandle >::iterator j;
1348  for( i = ents_to_remove.begin(); i != ents_to_remove.end(); ++i )
1349  {
1350  j = std::find( vect.begin(), vect.end(), *i );
1351  if( j != vect.end() ) vect.erase( j );
1352  }
1353 }

References moab::Range::begin(), and moab::Range::end().

◆ reset_times()

void reset_times ( )
static

Definition at line 1198 of file convert.cpp.

1199 {
1200  abs_time = clock();
1201 }

References abs_time.

Referenced by main().

◆ usage_error()

static void usage_error ( const char *  name)
static

Definition at line 147 of file convert.cpp.

148 {
149  print_usage( name, std::cerr );
150 #ifdef MOAB_HAVE_MPI
151  MPI_Finalize();
152 #endif
153  exit( USAGE_ERROR );
154 }

References print_usage(), and USAGE_ERROR.

Referenced by main().

◆ write_times()

void write_times ( std::ostream &  stream)
static

Definition at line 1203 of file convert.cpp.

1204 {
1205  clock_t abs_tm = clock();
1206  print_time( CLOCKS_PER_SEC, " ", abs_tm - abs_time, stream );
1207  abs_time = abs_tm;
1208 }

References abs_time, and print_time().

Referenced by main().

Variable Documentation

◆ abs_time

clock_t abs_time

Definition at line 1194 of file convert.cpp.

Referenced by reset_times(), and write_times().

◆ sys_time

clock_t sys_time

Definition at line 1194 of file convert.cpp.

◆ usr_time

clock_t usr_time

Definition at line 1194 of file convert.cpp.