Loading [MathJax]/extensions/tex2jax.js
Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
WriteHDF5.hpp
Go to the documentation of this file.
1 /** 2  * MOAB, a Mesh-Oriented datABase, is a software component for creating, 3  * storing and accessing finite element mesh data. 4  * 5  * Copyright 2004 Sandia Corporation. Under the terms of Contract 6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 7  * retains certain rights in this software. 8  * 9  * This library is free software; you can redistribute it and/or 10  * modify it under the terms of the GNU Lesser General Public 11  * License as published by the Free Software Foundation; either 12  * version 2.1 of the License, or (at your option) any later version. 13  * 14  */ 15  16 #ifndef WRITE_HDF5_HPP 17 #define WRITE_HDF5_HPP 18  19 #include <list> 20 #include "moab/MOABConfig.h" 21 #ifdef MOAB_HAVE_MPI // include this before HDF5 headers to avoid conflicts 22 #include "moab_mpi.h" 23 #endif 24 #include "moab_mpe.h" 25 #include "mhdf.h" 26 #include "moab/Forward.hpp" 27 #include "moab/Range.hpp" 28 #include "moab/WriterIface.hpp" 29 #include "moab/RangeMap.hpp" 30 #include "moab/WriteUtilIface.hpp" 31 #include "DebugOutput.hpp" 32 #include "HDF5Common.hpp" 33  34 namespace moab 35 { 36  37 class IODebugTrack; 38  39 /* If this define is not set, node->entity adjacencies will not be written */ 40 #undef MB_H5M_WRITE_NODE_ADJACENCIES 41  42 /** 43  * \brief Write mesh database to MOAB's native HDF5-based file format. 44  * \author Jason Kraftcheck 45  * \date 01 April 2004 46  */ 47 class WriteHDF5 : public WriterIface 48 { 49  50  public: 51  static WriterIface* factory( Interface* ); 52  53  WriteHDF5( Interface* iface ); 54  55  virtual ~WriteHDF5(); 56  57  /** Export specified meshsets to file 58  * \param filename The filename to export. 59  * \param export_sets Array of handles to sets to export, or NULL to export all. 60  * \param export_set_count Length of <code>export_sets</code> array. 61  */ 62  ErrorCode write_file( const char* filename, 63  const bool overwrite, 64  const FileOptions& opts, 65  const EntityHandle* export_sets, 66  const int export_set_count, 67  const std::vector< std::string >& qa_records, 68  const Tag* tag_list = NULL, 69  int num_tags = 0, 70  int user_dimension = 3 ); 71  72  /** The type to use for entity IDs w/in the file. 73  * 74  * NOTE: If this is changed, the value of id_type 75  * MUST be changed accordingly. 76  */ 77  typedef EntityHandle wid_t; // change the name, 78  // to avoid conflicts to /usr/include/x86_64-linux-gnu/bits/types.h : id_t , which is unsigned 79  // int 80  81  /** HDF5 type corresponding to type of wid_t */ 82  static const hid_t id_type; 83  84  struct ExportType 85  { 86  //! The type of the entities in the range 87  EntityType type; 88  //! The number of nodes per entity - not used for nodes and sets 89  int num_nodes; 90  91  virtual ~ExportType() {} 92  93  bool operator==( const ExportType& t ) const 94  { 95  return t.type == type && t.num_nodes == num_nodes; 96  } 97  bool operator!=( const ExportType& t ) const 98  { 99  return t.type != type || t.num_nodes != num_nodes; 100  } 101  bool operator<( const ExportType& t ) const 102  { 103  return type < t.type || ( type == t.type && num_nodes < t.num_nodes ); 104  } 105  }; 106  107  //! Range of entities, grouped by type, to export 108  struct ExportSet : public ExportType 109  { 110  //! The range of entities. 111  Range range; 112  //! The first Id allocated by the mhdf library. Entities in range have sequential IDs. 113  wid_t first_id; 114  //! The offset at which to begin writing this processor's data. 115  //! Always zero except for parallel IO. 116  long offset; 117  //! Offset for adjacency data. Always zero except for parallel IO 118  long adj_offset; 119  //! If doing parallel IO, largest number of entities to write 120  //! for any processor (needed to do collective IO). Zero if unused. 121  long max_num_ents, max_num_adjs; 122  //! The total number of entities that will be written to the file 123  //! for this group. For serial IO, this should always be range.size(). 124  //! For parallel IO, it will be the sum of range size over all processors. 125  //! For parallel IO, this value is undefined except for on the root 126  //! processor. 127  long total_num_ents; 128  129  bool operator<( const ExportType& other ) const 130  { 131  return type < other.type || ( type == other.type && num_nodes < other.num_nodes ); 132  } 133  134  bool operator<( std::pair< int, int > other ) const 135  { 136  return type < other.first || ( type == other.first && num_nodes < other.second ); 137  } 138  139  bool operator==( const ExportType& other ) const 140  { 141  return ( type == other.type && num_nodes == other.num_nodes ); 142  } 143  144  bool operator==( std::pair< int, int > other ) const 145  { 146  return ( type == other.first && num_nodes == other.second ); 147  } 148  149  const char* name() const; 150  }; 151  152  //! Tag to write to file. 153  struct TagDesc 154  { 155  //! The tag handle 156  Tag tag_id; 157  //! The offset at which to begin writting this processor's data. 158  //! Always zero except for parallel IO. 159  wid_t sparse_offset; 160  //! For variable-length tags, a second offset for the tag data table, 161  //! separate from the offset used for the ID and Index tables. 162  //! Always zero except for parallel IO. 163  wid_t var_data_offset; 164  //! Write sparse tag data (for serial, is always equal to !range.empty()) 165  bool write_sparse; 166  //! If doing parallel IO, largest number, over all processes, of entities 167  //! for which to write tag data. Zero if unused. 168  unsigned long max_num_ents; 169  //! For variable-length tags during parallel IO: the largest number 170  //! of tag values to be written on by any process, used to calculate 171  //! the total number of collective writes that all processes must do. 172  //! Zero for fixed-length tags or if not doing parallel IO. 173  unsigned long max_num_vals; 174  175  //! List of entity groups for which to write tag data in 176  //! dense format 177  std::vector< ExportType > dense_list; 178  179  bool have_dense( const ExportType& type ) const 180  { 181  return std::find( dense_list.begin(), dense_list.end(), type ) != dense_list.end(); 182  } 183  184  bool operator<( const TagDesc& ) const; 185  }; 186  187  /** Create attributes holding the HDF5 type handle for the 188  * type of a bunch of the default tags. 189  */ 190  // static ErrorCode register_known_tag_types( Interface* ); 191  192  //! Store old HDF5 error handling function 193  struct HDF5ErrorHandler 194  { 195  HDF5_Error_Func_Type func; 196  void* data; 197  }; 198  199  mhdf_FileHandle file_ptr() 200  { 201  return filePtr; 202  } 203  204  WriteUtilIface* write_util() 205  { 206  return writeUtil; 207  } 208  209  protected: 210  //! Store old HDF5 error handling function 211  HDF5ErrorHandler errorHandler; 212  213  /** Function to create the file. Virtual to allow override 214  * for parallel version. 215  */ 216  virtual ErrorCode parallel_create_file( const char* filename, 217  bool overwrite, 218  const std::vector< std::string >& qa_records, 219  const FileOptions& opts, 220  const Tag* tag_list, 221  int num_tags, 222  int dimension = 3, 223  double* times = 0 ); 224  virtual ErrorCode write_finished(); 225  virtual void debug_barrier_line( int lineno ); 226  227  //! Gather tags 228  ErrorCode gather_tags( const Tag* user_tag_list, int user_tag_list_length ); 229  230  /** Check if tag values for a given ExportSet should be written in dense format 231  * 232  *\param ents ExportSet to consider 233  *\param all_tagged Range containing all the entities in ents.range for 234  * which an explicit tag value is stored. Range may 235  * also contain entities not in ents.range, but may 236  * not contain entities in ents.range for which no tag 237  * value is stored. 238  *\param prefer_dense If true, will return true if at least 2/3 of the 239  * entities are tagged. This should not be passed as 240  * true if the tag does not have a default value, as 241  * tag values must be stored for all entities in the 242  * ExportSet for dense-formatted data. 243  */ 244  bool check_dense_format_tag( const ExportSet& ents, const Range& all_tagged, bool prefer_dense ); 245  246  /** Helper function for create-file 247  * 248  * Calculate the sum of the number of non-set adjacencies 249  * of all entities in the passed range. 250  */ 251  ErrorCode count_adjacencies( const Range& elements, wid_t& result ); 252  253  public: // make these public so helper classes in WriteHDF5Parallel can use them 254  /** Helper function for create-file 255  * 256  * Create zero-ed tables where element connectivity and 257  * adjacency data will be stored. 258  */ 259  ErrorCode create_elem_table( const ExportSet& block, long num_ents, long& first_id_out ); 260  261  /** Helper function for create-file 262  * 263  * Create zero-ed table where set descriptions will be written 264  */ 265  ErrorCode create_set_meta( long num_sets, long& first_id_out ); 266  267  protected: 268  /** Helper function for create-file 269  * 270  * Calculate total length of set contents and child tables. 271  */ 272  ErrorCode count_set_size( const Range& sets, 273  long& contents_length_out, 274  long& children_length_out, 275  long& parents_length_out ); 276  277  //! Get information about a meshset 278  ErrorCode get_set_info( EntityHandle set, 279  long& num_entities, 280  long& num_children, 281  long& num_parents, 282  unsigned long& flags ); 283  284  /** Helper function for create-file 285  * 286  * Create zero-ed tables where set data will be written. 287  */ 288  ErrorCode create_set_tables( long contents_length, long children_length, long parents_length ); 289  290  //! Write exodus-type QA info 291  ErrorCode write_qa( const std::vector< std::string >& list ); 292  293  //!\brief Get tagged entities for which to write tag values 294  ErrorCode get_num_sparse_tagged_entities( const TagDesc& tag, size_t& count ); 295  //!\brief Get tagged entities for which to write tag values 296  ErrorCode get_sparse_tagged_entities( const TagDesc& tag, Range& range ); 297  //!\brief Get entities that will be written to file 298  void get_write_entities( Range& range ); 299  300  //! The size of the data buffer (<code>dataBuffer</code>). 301  size_t bufferSize; 302  //! A memory buffer to use for all I/O operations. 303  char* dataBuffer; 304  305  //! Interface pointer passed to constructor 306  Interface* iFace; 307  //! Cached pointer to writeUtil interface. 308  WriteUtilIface* writeUtil; 309  310  //! The file handle from the mhdf library 311  mhdf_FileHandle filePtr; 312  313  //! Map from entity handles to file IDs 314  RangeMap< EntityHandle, wid_t > idMap; 315  316  //! The list elements to export. 317  std::list< ExportSet > exportList; 318  //! The list of nodes to export 319  ExportSet nodeSet; 320  //! The list of sets to export 321  ExportSet setSet; 322  323  const ExportSet* find( const ExportType& type ) const 324  { 325  if( type.type == MBVERTEX ) 326  return &nodeSet; 327  else if( type.type == MBENTITYSET ) 328  return &setSet; 329  else 330  { 331  std::list< ExportSet >::const_iterator it; 332  it = std::find( exportList.begin(), exportList.end(), type ); 333  return it == exportList.end() ? 0 : &*it; 334  } 335  } 336  337  //! Offset into set contents table (zero except for parallel) 338  unsigned long setContentsOffset; 339  //! Offset into set children table (zero except for parallel) 340  unsigned long setChildrenOffset, setParentsOffset; 341  //! The largest number of values to write 342  //! for any processor (needed to do collective IO). 343  long maxNumSetContents, maxNumSetChildren, maxNumSetParents; 344  //! Flags idicating if set data should be written. 345  //! For the normal (non-parallel) case, these values 346  //! will depend only on whether or not there is any 347  //! data to be written. For parallel-meshes, opening 348  //! the data table is collective so the values must 349  //! depend on whether or not any processor has meshsets 350  //! to be written. 351  bool writeSets, writeSetContents, writeSetChildren, writeSetParents; 352  353  //! Struct describing a set for which the contained and linked entity 354  //! lists are something other than the local values. Used to store 355  //! data for shared sets owned by this process when writing in parallel. 356  struct SpecialSetData 357  { 358  EntityHandle setHandle; 359  unsigned setFlags; 360  std::vector< wid_t > contentIds; 361  std::vector< wid_t > childIds; 362  std::vector< wid_t > parentIds; 363  }; 364  struct SpecSetLess 365  { 366  bool operator()( const SpecialSetData& a, SpecialSetData b ) const 367  { 368  return a.setHandle < b.setHandle; 369  } 370  }; 371  372  //! Array of special/shared sets, in order of handle value. 373  std::vector< SpecialSetData > specialSets; 374  const SpecialSetData* find_set_data( EntityHandle h ) const 375  { 376  return const_cast< WriteHDF5* >( this )->find_set_data( h ); 377  } 378  SpecialSetData* find_set_data( EntityHandle h ); 379  380  //! The list of tags to export 381  std::list< TagDesc > tagList; 382  383  //! True if doing parallel write 384  bool parallelWrite; 385  //! True if using collective IO calls for parallel write 386  bool collectiveIO; 387  //! True if writing dense-formatted tag data 388  bool writeTagDense; 389  390  //! Property set to pass to H5Dwrite calls. 391  //! For serial, should be H5P_DEFAULTS. 392  //! For parallel, may request collective IO. 393  hid_t writeProp; 394  395  //! Utility to log debug output 396  DebugOutput dbgOut; 397  398  static MPEState topState; 399  static MPEState subState; 400  401  //! Look for overlapping and/or missing writes 402  bool debugTrack; 403  404  void print_id_map() const; 405  void print_id_map( std::ostream& str, const char* prefix = "" ) const; 406  407  /** Helper function for create-file 408  * 409  * Write tag meta-info and create zero-ed table where 410  * tag values will be written. 411  *\param num_entities Number of entities for which to write tag data. 412  *\param var_len_total For variable-length tags, the total number of values 413  * in the data table. 414  */ 415  ErrorCode create_tag( const TagDesc& tag_data, unsigned long num_entities, unsigned long var_len_total ); 416  417  /**\brief add entities to idMap */ 418  ErrorCode assign_ids( const Range& entities, wid_t first_id ); 419  420  /** Get possibly compacted list of IDs for passed entities 421  * 422  * For the passed range of entities, determine if IDs 423  * can be compacted and write IDs to passed list. 424  * 425  * If the IDs are not compacted, the output list will contain 426  * a simple ordered list of IDs. 427  * 428  * If IDs are compacted, the output list will contain 429  * {start,count} pairs. 430  * 431  * If the ID list is compacted, ranged_list will be 'true'. 432  * Otherwise it will be 'false'. 433  */ 434  ErrorCode range_to_blocked_list( const Range& input_range, 435  std::vector< wid_t >& output_id_list, 436  bool& ranged_list ); 437  438  /** Get possibly compacted list of IDs for passed entities 439  * 440  * For the passed range of entities, determine if IDs 441  * can be compacted and write IDs to passed list. 442  * 443  * If the IDs are not compacted, the output list will contain 444  * a simple ordered list of IDs. 445  * 446  * If IDs are compacted, the output list will contain 447  * {start,count} pairs. 448  * 449  * If the ID list is compacted, ranged_list will be 'true'. 450  * Otherwise it will be 'false'. 451  */ 452  ErrorCode range_to_blocked_list( const EntityHandle* input_ranges, 453  size_t num_input_ranges, 454  std::vector< wid_t >& output_id_list, 455  bool& ranged_list ); 456  457  ErrorCode range_to_id_list( const Range& input_range, wid_t* array ); 458  //! Get IDs for entities 459  ErrorCode vector_to_id_list( const std::vector< EntityHandle >& input, 460  std::vector< wid_t >& output, 461  bool remove_non_written = false ); 462  //! Get IDs for entities 463  ErrorCode vector_to_id_list( const EntityHandle* input, wid_t* output, size_t num_entities ); 464  //! Get IDs for entities 465  ErrorCode vector_to_id_list( const EntityHandle* input, 466  size_t input_len, 467  wid_t* output, 468  size_t& output_len, 469  bool remove_non_written ); 470  471  /** When writing tags containing EntityHandles to file, need to convert tag 472  * data from EntityHandles to file IDs. This function does that. 473  * 474  * If the handle is not valid or does not correspond to an entity that will 475  * be written to the file, the file ID is set to zero. 476  *\param data The data buffer. As input, an array of EntityHandles. As 477  * output an array of file IDS, where the size of each integral 478  * file ID is the same as the size of EntityHandle. 479  *\param count The number of handles in the buffer. 480  *\return true if at least one of the handles is valid and will be written to 481  * the file or at least one of the handles is NULL (zero). false 482  * otherwise 483  */ 484  bool convert_handle_tag( EntityHandle* data, size_t count ) const; 485  bool convert_handle_tag( const EntityHandle* source, EntityHandle* dest, size_t count ) const; 486  487  /** Get IDs of adjacent entities. 488  * 489  * For all entities adjacent to the passed entity, if the 490  * adjacent entity is to be exported (ID is not zero), append 491  * the ID to the passed list. 492  */ 493  ErrorCode get_adjacencies( EntityHandle entity, std::vector< wid_t >& adj ); 494  495  //! get sum of lengths of tag values (as number of type) for 496  //! variable length tag data. 497  ErrorCode get_tag_data_length( const TagDesc& tag_info, const Range& range, unsigned long& result ); 498  499  private: 500  //! Do the actual work of write_file. Separated from write_file 501  //! for easier resource cleanup. 502  ErrorCode write_file_impl( const char* filename, 503  const bool overwrite, 504  const FileOptions& opts, 505  const EntityHandle* export_sets, 506  const int export_set_count, 507  const std::vector< std::string >& qa_records, 508  const Tag* tag_list, 509  int num_tags, 510  int user_dimension = 3 ); 511  512  ErrorCode init(); 513  514  ErrorCode serial_create_file( const char* filename, 515  bool overwrite, 516  const std::vector< std::string >& qa_records, 517  const Tag* tag_list, 518  int num_tags, 519  int dimension = 3 ); 520  521  /** Get all mesh to export from given list of sets. 522  * 523  * Populate exportSets, nodeSet and setSet with lists of 524  * entities to write. 525  * 526  * \param export_sets The list of meshsets to export 527  */ 528  ErrorCode gather_mesh_info( const std::vector< EntityHandle >& export_sets ); 529  530  //! Same as gather_mesh_info, except for entire mesh 531  ErrorCode gather_all_mesh(); 532  533  //! Initialize internal data structures from gathered mesh 534  ErrorCode initialize_mesh( const Range entities_by_dim[5] ); 535  536  /** Write out the nodes. 537  * 538  * Note: Assigns IDs to nodes. 539  */ 540  ErrorCode write_nodes(); 541  542  /** Write out element connectivity. 543  * 544  * Write connectivity for passed set of elements. 545  * 546  * Note: Assigns element IDs. 547  * Note: Must do write_nodes first so node IDs get assigned. 548  */ 549  ErrorCode write_elems( ExportSet& elemset ); 550  551  /** Write out meshsets 552  * 553  * Write passed set of meshsets, including parent/child relations. 554  * 555  * Note: Must have written nodes and element connectivity 556  * so entities have assigned IDs. 557  */ 558  ErrorCode write_sets( double* times ); 559  560  /** Write set contents/parents/children lists 561  * 562  *\param which_data Which set data to write (contents, parents, or children) 563  *\param handle HDF5 handle for data set in which to write data 564  *\param track Debugging tool 565  *\param ranged Will be populated with handles of sets for which 566  * contents were written in a range-compacted format. 567  * (mhdf_SET_RANGE_BIT). Should be null for parents/children. 568  *\param null_stripped Will be populated with handles of sets for which 569  * invalid or null handles were stripped from the contents 570  * list. This is only done for unordered sets. This argument 571  * should be null if writing parents/children because those 572  * lists are always ordered. 573  *\param set_sizes Will be populated with the length of the data written 574  * for those sets for which the handles were added to 575  * either \c ranged or \c null_stripped. Values are 576  * in handle order. 577  */ 578  ErrorCode write_set_data( const WriteUtilIface::EntityListType which_data, 579  const hid_t handle, 580  IODebugTrack& track, 581  Range* ranged = 0, 582  Range* null_stripped = 0, 583  std::vector< long >* set_sizes = 0 ); 584  585  /** Write adjacency info for passed set of elements 586  * 587  * Note: Must have written element connectivity so elements 588  * have IDs assigned. 589  */ 590  ErrorCode write_adjacencies( const ExportSet& export_set ); 591  592  /** Write tag information and data. 593  * 594  * Note: Must have already written nodes, elem connectivity and 595  * sets so that entities have IDs assigned. 596  */ 597  598  //! Write tag for all entities. 599  ErrorCode write_tag( const TagDesc& tag_data, double* times ); 600  601  //! Get element connectivity 602  ErrorCode get_connectivity( Range::const_iterator begin, 603  Range::const_iterator end, 604  int nodes_per_element, 605  wid_t* id_data_out ); 606  607  //! Get size data for tag 608  //!\param tag MOAB tag ID 609  //!\param moab_type Output: DataType for tag 610  //!\param num_bytes Output: MOAB tag size (bits for bit tags). 611  //! MB_VARIABLE_LENGTH for variable-length tags. 612  //!\param elem_size Output: Size of of the base data type of the 613  //! tag data (e.g. sizeof(double) if 614  //! moab_type == MB_TYPE_DOUBLE). 615  //! One for bit and opaque tags. 616  //!\param array_size Output: The number of valeus of size elem_size 617  //! for each tag. Always 1 for opaque data. 618  //! Nubmer of bits for bit tags. 619  //!\param file_type Output: mhdf type enumeration 620  //!\param hdf_type Output: Handle to HDF5 type object. Caller is 621  //! responsible for releasing this object 622  //! (calling H5Tclose). 623  ErrorCode get_tag_size( Tag tag, 624  DataType& moab_type, 625  int& num_bytes, 626  int& elem_size, 627  int& file_size, 628  mhdf_TagDataType& file_type, 629  hid_t& hdf_type ); 630  631  //! Write ID table for sparse tag 632  ErrorCode write_sparse_ids( const TagDesc& tag_data, 633  const Range& range, 634  hid_t table_handle, 635  size_t table_size, 636  const char* name = 0 ); 637  638  //! Write fixed-length tag data in sparse format 639  ErrorCode write_sparse_tag( const TagDesc& tag_data, 640  const std::string& tag_name, 641  DataType tag_data_type, 642  hid_t hdf5_data_type, 643  int hdf5_type_size ); 644  645  //! Write end index data_set for a variable-length tag 646  ErrorCode write_var_len_indices( const TagDesc& tag_data, 647  const Range& range, 648  hid_t idx_table, 649  size_t table_size, 650  int type_size, 651  const char* name = 0 ); 652  653  //! Write tag value data_set for a variable-length tag 654  ErrorCode write_var_len_data( const TagDesc& tag_data, 655  const Range& range, 656  hid_t table, 657  size_t table_size, 658  bool handle_tag, 659  hid_t hdf_type, 660  int type_size, 661  const char* name = 0 ); 662  663  //! Write varialbe-length tag data 664  ErrorCode write_var_len_tag( const TagDesc& tag_info, 665  const std::string& tag_name, 666  DataType tag_data_type, 667  hid_t hdf5_type, 668  int hdf5_type_size ); 669  670  //! Write dense-formatted tag data 671  ErrorCode write_dense_tag( const TagDesc& tag_data, 672  const ExportSet& elem_data, 673  const std::string& tag_name, 674  DataType tag_data_type, 675  hid_t hdf5_data_type, 676  int hdf5_type_size ); 677  678  //! Write data for fixed-size tag 679  ErrorCode write_tag_values( Tag tag_id, 680  hid_t data_table, 681  unsigned long data_offset, 682  const Range& range, 683  DataType tag_data_type, 684  hid_t hdf5_data_type, 685  int hdf5_type_size, 686  unsigned long max_num_ents, 687  IODebugTrack& debug_track ); 688  689  protected: 690  enum TimingValues 691  { 692  TOTAL_TIME = 0, 693  GATHER_TIME, 694  CREATE_TIME, 695  CREATE_NODE_TIME, 696  NEGOTIATE_TYPES_TIME, 697  CREATE_ELEM_TIME, 698  FILEID_EXCHANGE_TIME, 699  CREATE_ADJ_TIME, 700  CREATE_SET_TIME, 701  SHARED_SET_IDS, 702  SHARED_SET_CONTENTS, 703  SET_OFFSET_TIME, 704  CREATE_TAG_TIME, 705  COORD_TIME, 706  CONN_TIME, 707  SET_TIME, 708  SET_META, 709  SET_CONTENT, 710  SET_PARENT, 711  SET_CHILD, 712  ADJ_TIME, 713  TAG_TIME, 714  DENSE_TAG_TIME, 715  SPARSE_TAG_TIME, 716  VARLEN_TAG_TIME, 717  NUM_TIMES 718  }; 719  720  virtual void print_times( const double times[NUM_TIMES] ) const; 721 }; 722  723 } // namespace moab 724  725 #endif