1 // Copyright(C) 1999-2020 National Technology & Engineering Solutions 2 // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with 3 // NTESS, the U.S. Government retains certain rights in this software. 4 // 5 // See packages/seacas/LICENSE for details 6 7 #ifndef IOSS_Ioss_DatabaseIO_h 8 #define IOSS_Ioss_DatabaseIO_h 9 10 #include "vtk_ioss_mangle.h" 11 12 #include <Ioss_BoundingBox.h> 13 #include <Ioss_CodeTypes.h> 14 #include <Ioss_DBUsage.h> // for DatabaseUsage, etc 15 #include <Ioss_DataSize.h> // for DataSize 16 #include <Ioss_EntityType.h> // for EntityType 17 #include <Ioss_Map.h> 18 #include <Ioss_ParallelUtils.h> // for ParallelUtils 19 #include <Ioss_PropertyManager.h> // for PropertyManager 20 #include <Ioss_State.h> // for State, State::STATE_INVALID 21 #include <Ioss_SurfaceSplit.h> // for SurfaceSplitType 22 #include <chrono> 23 #include <cstddef> // for size_t, nullptr 24 #include <cstdint> // for int64_t 25 #include <map> // for map 26 #include <string> // for string 27 #include <utility> // for pair 28 #include <vector> // for vector 29 30 namespace Ioss { 31 class Assembly; 32 class Blob; 33 class CommSet; 34 class EdgeBlock; 35 class EdgeSet; 36 class ElementBlock; 37 class ElementSet; 38 class ElementTopology; 39 class FaceBlock; 40 class FaceSet; 41 class Field; 42 class GroupingEntity; 43 class NodeBlock; 44 class NodeSet; 45 class Region; 46 class SideBlock; 47 class SideSet; 48 class StructuredBlock; 49 } // namespace Ioss 50 51 namespace Ioss { 52 class EntityBlock; 53 54 // Contains (parent_element, side) topology pairs 55 using TopoContainer = std::vector<std::pair<const ElementTopology *, const ElementTopology *>>; 56 57 /** \brief An input or output Database. 58 * 59 */ 60 class DatabaseIO 61 { 62 public: 63 friend class SerializeIO; 64 65 DatabaseIO() = delete; 66 DatabaseIO(const DatabaseIO &) = delete; 67 DatabaseIO &operator=(const DatabaseIO &) = delete; 68 69 /** \brief Check to see if database state is OK. 70 * 71 * \param[in] write_message If true, then output a warning message indicating the problem. 72 * \param[in,out] error_message If non-null on input, then a warning message on output. 73 * \param[in,out] bad_count If non-null on input, then count of the number of processors 74 * where the file does not exist on output. If ok returns false, but 75 * *bad_count==0, 76 * then the routine does not support this argument. 77 * \returns True if database state is OK. False if not. 78 */ 79 bool ok(bool write_message = false, std::string *error_message = nullptr, 80 int *bad_count = nullptr) const 81 { 82 IOSS_FUNC_ENTER(m_); 83 return ok__(write_message, error_message, bad_count); 84 } 85 86 // Check capabilities of input/output database... Returns an 87 // unsigned int with the supported Ioss::EntityTypes or'ed 88 // together. If "return_value & Ioss::EntityType" is set, then the 89 // database supports that type (e.g. return_value & Ioss::FACESET) 90 virtual unsigned entity_field_support() const = 0; 91 using_parallel_io()92 bool using_parallel_io() const { return usingParallelIO; } 93 94 /** \brief Get the local (process-specific) node number corresponding to a global node number. 95 * 96 * \param[in] global The global node number 97 * \param[in] must_exist If true, error will occur if the global node number is not 98 * mapped to any local node number on the current process. 99 * \returns The local node number 100 */ node_global_to_local(int64_t global,bool must_exist)101 int64_t node_global_to_local(int64_t global, bool must_exist) const 102 { 103 IOSS_FUNC_ENTER(m_); 104 return node_global_to_local__(global, must_exist); 105 } 106 element_global_to_local(int64_t global)107 int64_t element_global_to_local(int64_t global) const 108 { 109 IOSS_FUNC_ENTER(m_); 110 return element_global_to_local__(global); 111 } 112 113 /** If there is a single block of nodes in the model, then it is 114 * considered a node_major() database. If instead the nodes are 115 * local to each element block or structured block, then it is 116 * not a node_major database. Exodus is node major, CGNS is not. 117 */ node_major()118 virtual bool node_major() const { return true; } 119 120 virtual ~DatabaseIO(); 121 122 // Eliminate as much memory as possible, but still retain meta data information 123 // Typically, eliminate the maps... release_memory()124 void release_memory() 125 { 126 IOSS_FUNC_ENTER(m_); 127 release_memory__(); 128 } 129 130 // Do anything that might be needed to the database prior to it 131 // being closed and destructed. finalize_database()132 virtual void finalize_database() const {} 133 134 // Let's save the name on disk after Filename gets modified, e.g: decoded_filename set_pfsname(const std::string & name)135 void set_pfsname(const std::string &name) const { pfsName = name; } 136 get_pfsname()137 std::string get_pfsname() const { return pfsName; } 138 139 /** \brief this will be the name in BB namespace 140 */ set_dwname(const std::string & name)141 void set_dwname(const std::string &name) const { bbName = name; } 142 get_dwname()143 std::string get_dwname() const 144 { 145 if (!bbName.empty() && !is_input() && using_dw()) { 146 return bbName; 147 } 148 else { 149 return get_filename(); 150 } 151 } 152 153 /** \brief We call this ONLY after we assure that using_dw() is TRUE 154 * \ returns mount point of Datawarp namespace, e.g: `/opt/cray/....<jobid>` 155 */ get_dwPath()156 std::string get_dwPath() const { return dwPath; } 157 158 /** Determine whether Cray Datawarp module is loaded and we have BB capacity allocated for this 159 * job ( i.e: DW_JOB_STRIPED is set) && IOSS property to use DATAWARP is set to Y/YES (i.e 160 * environmental variable ENABLE_DATAWARP) . If we are using DW then set some pathnames for 161 * writing directly to BB instead of PFS(i.e Lustre) 162 */ 163 void check_setDW() const; 164 165 /** Set if Cray Datawarp exists and allocated space is found , i.e PATH to DW name space 166 */ using_dw()167 bool using_dw() const { return usingDataWarp; } 168 169 /** \brief Get the file name associated with the database. 170 * 171 * \returns The database file name. 172 */ get_filename()173 std::string get_filename() const { return DBFilename; } 174 175 /** For the database types that support it, return an integer `handle` 176 * through which a client can directly access the underlying file. 177 * Please use sparingly and with discretion. Basically, a kluge 178 */ get_file_pointer()179 virtual int get_file_pointer() const { return 0; } 180 181 /** \brief Get a file-per-processor filename associated with the database. 182 * 183 * \ returns The file-per-processor name for a file on this processor. 184 */ 185 const std::string &decoded_filename() const; 186 187 /** Return a string specifying underlying format of database (exodus, cgns, ...) */ 188 virtual const std::string get_format() const = 0; 189 190 /** \brief Determine whether the database is an input database. 191 * 192 * \returns True if the database is an input database. False otherwise. 193 */ is_input()194 bool is_input() const { return isInput; } 195 196 /** \brief Get the Ioss::DatabaseUsage type of the database. 197 * 198 * \returns The Ioss::DatabaseUsage type of the database. 199 */ usage()200 Ioss::DatabaseUsage usage() const { return dbUsage; } 201 202 /** \brief Determine whether the database needs information about process ownership of nodes. 203 * 204 * \returns True if database needs information about process ownership of nodes. 205 */ needs_shared_node_information()206 virtual bool needs_shared_node_information() const { return false; } 207 208 Ioss::IfDatabaseExistsBehavior open_create_behavior() const; 209 set_region(Region * region)210 void set_region(Region *region) { region_ = region; } 211 212 /** \brief If we are planning to use BB(aka Burst Buffer) service, we will call 213 * simple C API provided by Cray DataWarp module. 214 * 215 * Note: We would only like to use BB during write to avoid cache coherency issues during 216 * read. `dwPath` is the DW namespace which gets set during runtime from environment variable 217 * DW_JOB_STRIPED. Afterword, `using_dw()` function is used extensively for filename redirection 218 * for all related subsequent functions(e.g: get_filename, get_file_ptr etc) once burst buffer 219 * is found and set to be used. 220 */ 221 void openDW(const std::string &filename) const; 222 223 /** \brief Function which invokes stageout from BB to Disk, prior to completion of final close 224 */ 225 void closeDW() const; 226 openDatabase()227 void openDatabase() const 228 { 229 IOSS_FUNC_ENTER(m_); 230 openDatabase__(); 231 } 232 closeDatabase()233 void closeDatabase() const 234 { 235 IOSS_FUNC_ENTER(m_); 236 closeDatabase__(); 237 } 238 flush_database()239 void flush_database() const 240 { 241 IOSS_FUNC_ENTER(m_); 242 flush_database__(); 243 } 244 245 /** \brief If a database type supports groups and if the database 246 * contains groups, open the specified group. 247 * 248 * If the group_name begins with '/', it specifies the absolute path 249 * name from the root with '/' separating groups. Otherwise, the 250 * group_name specifies a child group of the currently active group. 251 * If group_name == "/" then the root group is opened. 252 * 253 * \param[in] group_name The name of the group to open. 254 * \returns True if successful. 255 */ open_group(const std::string & group_name)256 bool open_group(const std::string &group_name) 257 { 258 IOSS_FUNC_ENTER(m_); 259 return open_group__(group_name); 260 } 261 262 /** \brief If a database type supports groups, create the specified 263 * group as a child of the current group. 264 * 265 * The name of the group must not contain a '/' character. 266 * If the command is successful, then the group will be the 267 * active group for all subsequent writes to the database. 268 * 269 * \param[in] group_name The name of the subgroup to create. 270 * \returns True if successful. 271 */ create_subgroup(const std::string & group_name)272 bool create_subgroup(const std::string &group_name) 273 { 274 IOSS_FUNC_ENTER(m_); 275 return create_subgroup__(group_name); 276 } 277 278 /** \brief Set the database to the given State. 279 * 280 * All transitions must begin from the 'STATE_CLOSED' state or be to 281 * the 'STATE_CLOSED' state (There are no nested begin/end pairs at 282 * this time.) 283 * 284 * The database state is automatically set when Region::begin_mode is called 285 * for its associated region, so it may not be necessary to call this method 286 * directly. 287 * 288 * \param[in] state The new State to which the database should be set. 289 * \returns True if successful. 290 * 291 */ begin(Ioss::State state)292 bool begin(Ioss::State state) 293 { 294 IOSS_FUNC_ENTER(m_); 295 return begin__(state); 296 } 297 298 /** \brief Return the database to STATE_CLOSED. 299 * 300 * The database is automatically set to STATE_CLOSED when Region::end_mode 301 * is called for its associated region, so it may not be necessary to call this 302 * method directly. 303 * 304 * \param[in] state The State to end, i.e. the current state. 305 * \returns True if successful. 306 * 307 */ end(Ioss::State state)308 bool end(Ioss::State state) 309 { 310 IOSS_FUNC_ENTER(m_); 311 return end__(state); 312 } 313 314 bool begin_state(int state, double time); 315 bool end_state(int state, double time); 316 317 // Metadata-related functions. read_meta_data()318 void read_meta_data() 319 { 320 IOSS_FUNC_ENTER(m_); 321 return read_meta_data__(); 322 } 323 get_step_times()324 void get_step_times() 325 { 326 IOSS_FUNC_ENTER(m_); 327 return get_step_times__(); 328 } 329 internal_edges_available()330 virtual bool internal_edges_available() const { return false; } internal_faces_available()331 virtual bool internal_faces_available() const { return false; } 332 333 // Information Records: 334 335 /** \brief Get all information records (informative strings) for the database. 336 * 337 * \returns The informative strings. 338 */ get_information_records()339 const std::vector<std::string> &get_information_records() const { return informationRecords; } 340 void add_information_records(const std::vector<std::string> &info); 341 void add_information_record(const std::string &info); 342 343 // QA Records: 344 345 /** \brief Get all QA records, each of which consists of 4 strings, from the database 346 * 347 * The 4 strings that make up a database QA record are: 348 * 349 * 1. A descriptive code name, such as the application that modified the database. 350 * 351 * 2. A descriptive string, such as the version of the application that modified the database. 352 * 353 * 3. A relevant date, such as the date the database was modified. 354 * 355 * 4. A relevant time, such as the time the database was modified. 356 * 357 * \returns All QA records in a single vector. Every 4 consecutive elements of the 358 * vector make up a single QA record. 359 */ get_qa_records()360 const std::vector<std::string> &get_qa_records() const { return qaRecords; } 361 void add_qa_record(const std::string &code, const std::string &code_qa, const std::string &date, 362 const std::string &time); 363 get_logging()364 bool get_logging() const { return doLogging && !singleProcOnly; } set_logging(bool on_off)365 void set_logging(bool on_off) { doLogging = on_off; } 366 367 // The get_field and put_field functions are just a wrapper around the 368 // pure virtual get_field_internal and put_field_internal functions, 369 // but this lets me add some debug/checking/common code to the 370 // functions without having to do it in the calling code or in the 371 // derived classes code. This also fulfills the heuristic that a 372 // public interface should not contain pure virtual functions. 373 template <typename T> get_field(const T * reg,const Field & field,void * data,size_t data_size)374 int64_t get_field(const T *reg, const Field &field, void *data, size_t data_size) const 375 { 376 IOSS_FUNC_ENTER(m_); 377 verify_and_log(reg, field, 1); 378 int64_t retval = get_field_internal(reg, field, data, data_size); 379 verify_and_log(nullptr, field, 1); 380 return retval; 381 } 382 383 template <typename T> put_field(const T * reg,const Field & field,void * data,size_t data_size)384 int64_t put_field(const T *reg, const Field &field, void *data, size_t data_size) const 385 { 386 IOSS_FUNC_ENTER(m_); 387 verify_and_log(reg, field, 0); 388 int64_t retval = put_field_internal(reg, field, data, data_size); 389 verify_and_log(nullptr, field, 0); 390 return retval; 391 } 392 393 /** Determine whether application will make field data get/put calls parallel consistently. 394 * 395 * True is default and required for parallel-io databases. 396 * Even if false, metadata operations must be called by all processors. 397 * 398 * \returns True if application will make field data get/put calls parallel consistently. 399 * 400 */ is_parallel_consistent()401 bool is_parallel_consistent() const { return isParallelConsistent; } set_parallel_consistency(bool on_off)402 void set_parallel_consistency(bool on_off) { isParallelConsistent = on_off; } 403 get_use_generic_canonical_name()404 bool get_use_generic_canonical_name() const { return useGenericCanonicalName; } set_use_generic_canonical_name(bool yes_no)405 void set_use_generic_canonical_name(bool yes_no) { useGenericCanonicalName = yes_no; } 406 ignore_database_names()407 bool ignore_database_names() const { return ignoreDatabaseNames; } ignore_database_names(bool yes_no)408 void ignore_database_names(bool yes_no) { ignoreDatabaseNames = yes_no; } 409 410 /** \brief Get the length of the longest name in the database file. 411 * 412 * \returns The length, or 0 for unlimited. 413 */ maximum_symbol_length()414 virtual int maximum_symbol_length() const { return 0; } // Default is unlimited... set_maximum_symbol_length(int)415 virtual void set_maximum_symbol_length(int /* requested_symbol_size */) { 416 } // Default does nothing... 417 get_field_separator()418 char get_field_separator() const { return fieldSeparator; } get_field_recognition()419 bool get_field_recognition() const { return enableFieldRecognition; } 420 void set_field_separator(char separator); set_field_recognition(bool yes_no)421 void set_field_recognition(bool yes_no) { enableFieldRecognition = yes_no; } 422 set_lower_case_variable_names(bool true_false)423 void set_lower_case_variable_names(bool true_false) const 424 { 425 lowerCaseVariableNames = true_false; 426 } 427 428 /* \brief Set the method used to split sidesets into homogeneous blocks. 429 * 430 * \param[in] split_type The desired method. 431 * 432 */ set_surface_split_type(Ioss::SurfaceSplitType split_type)433 void set_surface_split_type(Ioss::SurfaceSplitType split_type) { splitType = split_type; } get_surface_split_type()434 Ioss::SurfaceSplitType get_surface_split_type() const { return splitType; } 435 436 void set_block_omissions(const std::vector<std::string> &omissions, 437 const std::vector<std::string> &inclusions = {}); 438 get_block_adjacencies(const Ioss::ElementBlock * eb,std::vector<std::string> & block_adjacency)439 void get_block_adjacencies(const Ioss::ElementBlock *eb, 440 std::vector<std::string> &block_adjacency) const 441 { 442 return get_block_adjacencies__(eb, block_adjacency); 443 } compute_block_membership(Ioss::SideBlock * efblock,std::vector<std::string> & block_membership)444 void compute_block_membership(Ioss::SideBlock * efblock, 445 std::vector<std::string> &block_membership) const 446 { 447 return compute_block_membership__(efblock, block_membership); 448 } 449 450 AxisAlignedBoundingBox get_bounding_box(const Ioss::ElementBlock *eb) const; 451 AxisAlignedBoundingBox get_bounding_box(const Ioss::StructuredBlock *sb) const; 452 453 virtual int int_byte_size_db() const = 0; //! Returns 4 or 8 454 int int_byte_size_api() const; //! Returns 4 or 8 455 virtual void set_int_byte_size_api(Ioss::DataSize size) const; 456 457 /*! 458 * The owning region of this database. 459 */ get_region()460 Region *get_region() const { return region_; } 461 462 /*! 463 * The overlay_count specifies the number of restart outputs 464 * which will be overlaid on top of the currently written 465 * step before advancing to the next step on the restart 466 * database. 467 * 468 * For example, if restarts are being output every 0.1 469 * seconds and the overlay count is specified as 2, then 470 * restart will write time 0.1 to step 1 of the database. 471 * It will then write 0.2 and 0.3 also to step 1. It will 472 * then increment the database step and write 0.4 to step 2; 473 * overlay 0.5 and 0.6 on step 2... At the end of the 474 * analysis, assuming it runs to completion, the database 475 * would have times 0.3, 0.6, 0.9, ... However, if there 476 * were a problem during the analysis, the last step on the 477 * database would contain an intermediate step. 478 * 479 * The cycle_count specifies the number of restart steps 480 * which will be written to the restart database before 481 * previously written steps are overwritten. 482 * 483 * For example, if the cycle count is 5 and restart is written every 0.1 484 * seconds, the restart system will write data at times 0.1, 0.2, 0.3, 485 * 0.4, 0.5 to the database. 486 * 487 * It will then overwrite the first step with data from time 0.6, the 488 * second with time 0.7. At time 0.8, the database would contain data at 489 * times 0.6, 0.7, 0.8, 0.4, 0.5. Note that time will not necessarily be 490 * monotonically increasing on a database that specifies the cycle 491 * count. 492 * 493 * The cycle count and overlay count can both be used at the same time 494 * also. The basic formula is: 495 * 496 * db_step = (((output_step - 1) / overlay) % cycle) + 1 497 * 498 * where "output_step" is the step that this would have been on the 499 * database in a normal write (1,2,3,....) and "db_step" is the step 500 * number that this will be written to. 501 * 502 * If you only want the last step available on the database, 503 * use set_cycle_count(1) 504 */ set_cycle_count(int count)505 void set_cycle_count(int count) const { cycleCount = count; } get_cycle_count()506 int get_cycle_count() const { return cycleCount; } set_overlay_count(int count)507 void set_overlay_count(int count) const { overlayCount = count; } get_overlay_count()508 int get_overlay_count() const { return overlayCount; } set_file_per_state(bool yes_no)509 void set_file_per_state(bool yes_no) const { filePerState = yes_no; } get_file_per_state()510 bool get_file_per_state() const { return filePerState; } 511 set_time_scale_factor(double factor)512 void set_time_scale_factor(double factor) { timeScaleFactor = factor; } 513 util()514 const Ioss::ParallelUtils & util() const { return util_; } get_property_manager()515 const Ioss::PropertyManager &get_property_manager() const { return properties; } 516 /** \brief Get the processor that this mesh database is on. 517 * 518 * \returns The processor that this mesh database is on. 519 */ parallel_rank()520 int parallel_rank() const { return myProcessor; } parallel_size()521 int parallel_size() const { return util().parallel_size(); } is_parallel()522 bool is_parallel() const { return isParallel; } 523 progress(const std::string & output)524 void progress(const std::string &output) const 525 { 526 if (m_enableTracing) { 527 util().progress(output); 528 } 529 } 530 531 protected: 532 DatabaseIO(Region *region, std::string filename, Ioss::DatabaseUsage db_usage, 533 MPI_Comm communicator, const Ioss::PropertyManager &props); 534 535 /*! 536 * The properties member data contains properties that can be 537 * used to set database-specific options. Examples include 538 * compression, name lengths, integer sizes, floating point 539 * sizes. By convention, the property name is all 540 * uppercase. Some existing properties recognized by the Exodus 541 * DatabaseIO class are: 542 * 543 * | Property | Value 544 * |-----------------------|------------------- 545 * | COMPRESSION_LEVEL | In the range [0..9]. A value of 0 indicates no compression 546 * | COMPRESSION_SHUFFLE | (true/false) to enable/disable hdf5's shuffle compression 547 * algorithm. 548 * | FILE_TYPE | netcdf4 549 * | MAXIMUM_NAME_LENGTH | Maximum length of names that will be returned/passed via api call. 550 * | INTEGER_SIZE_DB | 4 or 8 indicating byte size of integers stored on the database. 551 * | INTEGER_SIZE_API | 4 or 8 indicating byte size of integers used in api functions. 552 * | LOGGING | (true/false) to enable/disable logging of field input/output 553 */ 554 555 Ioss::PropertyManager properties; 556 557 /*! 558 * Utility function that may be used by derived classes. 559 * Determines whether all elements in the model have the same side 560 * topology. This can be used to speed-up certain algorithms since 561 * they don't have to check each side (or group of sides) 562 * individually. 563 */ 564 void set_common_side_topology() const; 565 ElementTopology *commonSideTopology{nullptr}; 566 567 template <typename T> 568 void create_groups(const std::string &property_name, EntityType type, 569 const std::string &type_name, const T *set_type); 570 template <typename T> 571 void create_group(EntityType type, const std::string &type_name, 572 const std::vector<std::string> &group_spec, const T *set_type); 573 574 // Create new sets as groups of existing exodus sets... 575 void handle_groups(); 576 577 /*! 578 * Filename that this Database is connected with. Derived 579 * DatabaseIO classes may need to change this if the passed in 580 * filename is not the same as the filename actually used E.g., 581 * the Ioex_DatabaseIO (exodusII) changes if this is a parallel 582 * run since the passed in filename is just the basename, not the 583 * processor-specific filename. 584 */ 585 std::string originalDBFilename; 586 std::string DBFilename; 587 mutable std::string decodedFilename; 588 589 /*! 590 * `bbName` is a temporary swizzled name which resides inside Burst Buffer namespace. 591 * This is a private trivial mapped name vs original `DBFilename` (which resides in 592 * permanent storage backed by parallel filesystem. 593 * `dwPath` is global BB mountpoint for current job with requested capacity via SLURM \c \#DW 594 * directive. `usingDataWarp` -- a boolean, for convenience of use so that we don't have to do 595 * getenv() calls to see if BB present. 596 */ 597 mutable std::string bbName{}; 598 mutable std::string pfsName{}; 599 mutable std::string dwPath{}; 600 601 mutable Ioss::State dbState{STATE_INVALID}; 602 603 int myProcessor{0}; //!< number of processor this database is for 604 605 int64_t nodeCount{0}; 606 int64_t elementCount{0}; 607 608 /*! 609 * Check the topology of all face/element pairs in the model and 610 * fill the "TopoContainer faceTopology" variable with the 611 * unique pairs. This information is used for the 612 * faceblock/facesets and edgeblock/edgesets. If the 613 * 'topo_dimension' is 2, then face/element pairs are generated; if 614 * 'topo_dimension' is 1, then edge/element pairs are generated. 615 */ 616 void check_side_topology() const; 617 618 /// Used to speed up faceblock/edgeblock calculations. 619 TopoContainer sideTopology; 620 621 /*! Typically used for restart output, but can be used for all output... 622 * Maximum number of states on the output file. Overwrite the existing 623 * steps in a cyclic manner once exceed this count. Note that this breaks 624 * the convention that times be monotonically increasing on an exodusII file. 625 * Used by derived classes if they support this capability... 626 */ 627 mutable int cycleCount{0}; 628 629 mutable int overlayCount{0}; 630 631 /*! Scale the time read/written from/to the file by the specified 632 scaleFactor. If the database times are 0.1, 0.2, 0.3 and the 633 scaleFactor is 20, then the application will think that the 634 times read are 20, 40, 60. 635 636 If specified for an output database, then the analysis time 637 is divided by the scaleFactor time prior to output. 638 */ 639 double timeScaleFactor{1.0}; 640 641 Ioss::SurfaceSplitType splitType{SPLIT_BY_TOPOLOGIES}; 642 Ioss::DatabaseUsage dbUsage; 643 644 mutable Ioss::DataSize dbIntSizeAPI{USE_INT32_API}; 645 646 /*! EXPERIMENTAL If this is true, then each state (timestep) 647 * output will be directed to a separate file. Currently this is 648 * only implemented for the exodus (parallel or serial, single 649 * file or fpp) database type. 650 */ 651 mutable bool filePerState{false}; 652 mutable bool usingDataWarp{false}; 653 bool isParallel{false}; //!< true if running in parallel 654 655 mutable bool lowerCaseVariableNames{true}; 656 bool usingParallelIO{false}; 657 658 // List of element blocks that should be omitted or included from 659 // this model. Surfaces will take this into account while 660 // splitting; however, node and nodesets will not be filtered 661 // (perhaps this will be done at a later time...) NOTE: All local 662 // element ids and offsets are still calculated assuming that the 663 // blocks exist in the model... 664 // Only one of these can have values and the other must be empty. 665 std::vector<std::string> blockOmissions; 666 std::vector<std::string> blockInclusions; 667 668 std::vector<std::string> informationRecords; 669 std::vector<std::string> qaRecords; 670 671 //---Node Map -- Maps internal (1..NUMNP) ids to global ids used on the 672 // application side. global = nodeMap[local] 673 mutable Ioss::Map nodeMap{"node", DBFilename, myProcessor}; 674 mutable Ioss::Map edgeMap{"edge", DBFilename, myProcessor}; 675 mutable Ioss::Map faceMap{"face", DBFilename, myProcessor}; 676 mutable Ioss::Map elemMap{"element", DBFilename, myProcessor}; 677 678 mutable std::vector<std::vector<bool>> blockAdjacency; 679 680 virtual void openDatabase__() const; 681 virtual void closeDatabase__() const; flush_database__()682 virtual void flush_database__() const {} 683 684 private: ok__(bool,std::string *,int * bad_count)685 virtual bool ok__(bool /* write_message */, std::string * /* error_message */, 686 int *bad_count) const 687 { 688 if (bad_count != nullptr) { 689 *bad_count = 0; 690 } 691 return dbState != Ioss::STATE_INVALID; 692 } 693 node_global_to_local__(int64_t global,bool must_exist)694 virtual int64_t node_global_to_local__(int64_t global, bool must_exist) const 695 { 696 return nodeMap.global_to_local(global, must_exist); 697 } 698 element_global_to_local__(int64_t global)699 virtual int64_t element_global_to_local__(int64_t global) const 700 { 701 return elemMap.global_to_local(global); 702 } 703 release_memory__()704 virtual void release_memory__() 705 { 706 nodeMap.release_memory(); 707 edgeMap.release_memory(); 708 faceMap.release_memory(); 709 elemMap.release_memory(); 710 } 711 open_group__(const std::string &)712 virtual bool open_group__(const std::string & /* group_name */) { return false; } create_subgroup__(const std::string &)713 virtual bool create_subgroup__(const std::string & /* group_name */) { return false; } 714 715 virtual bool begin__(Ioss::State state) = 0; 716 virtual bool end__(Ioss::State state) = 0; 717 718 virtual void read_meta_data__() = 0; get_step_times__()719 virtual void get_step_times__() {} 720 721 virtual bool begin_state__(int state, double time); 722 virtual bool end_state__(int state, double time); 723 724 void get_block_adjacencies__(const Ioss::ElementBlock *eb, 725 std::vector<std::string> &block_adjacency) const; 726 compute_block_membership__(Ioss::SideBlock *,std::vector<std::string> &)727 virtual void compute_block_membership__(Ioss::SideBlock * /* efblock */, 728 std::vector<std::string> & /* block_membership */) const 729 { 730 } 731 732 void compute_block_adjacencies() const; 733 734 void verify_and_log(const GroupingEntity *ge, const Field &field, int in_out) const; 735 736 virtual int64_t get_field_internal(const Region *reg, const Field &field, void *data, 737 size_t data_size) const = 0; 738 virtual int64_t get_field_internal(const NodeBlock *nb, const Field &field, void *data, 739 size_t data_size) const = 0; 740 virtual int64_t get_field_internal(const EdgeBlock *nb, const Field &field, void *data, 741 size_t data_size) const = 0; 742 virtual int64_t get_field_internal(const FaceBlock *nb, const Field &field, void *data, 743 size_t data_size) const = 0; 744 virtual int64_t get_field_internal(const ElementBlock *eb, const Field &field, void *data, 745 size_t data_size) const = 0; 746 virtual int64_t get_field_internal(const SideBlock *fb, const Field &field, void *data, 747 size_t data_size) const = 0; 748 virtual int64_t get_field_internal(const NodeSet *ns, const Field &field, void *data, 749 size_t data_size) const = 0; 750 virtual int64_t get_field_internal(const EdgeSet *ns, const Field &field, void *data, 751 size_t data_size) const = 0; 752 virtual int64_t get_field_internal(const FaceSet *ns, const Field &field, void *data, 753 size_t data_size) const = 0; 754 virtual int64_t get_field_internal(const ElementSet *ns, const Field &field, void *data, 755 size_t data_size) const = 0; 756 virtual int64_t get_field_internal(const SideSet *fs, const Field &field, void *data, 757 size_t data_size) const = 0; 758 virtual int64_t get_field_internal(const CommSet *cs, const Field &field, void *data, 759 size_t data_size) const = 0; 760 virtual int64_t get_field_internal(const Assembly * /*as*/, const Field & /*field*/, 761 void * /*data*/, size_t /*data_size*/) const = 0; 762 virtual int64_t get_field_internal(const Blob * /*bl*/, const Field & /*field*/, 763 void * /*data*/, size_t /*data_size*/) const = 0; 764 virtual int64_t get_field_internal(const StructuredBlock * /*sb*/, const Field & /*field*/, 765 void * /*data*/, size_t /*data_size*/) const = 0; 766 767 virtual int64_t put_field_internal(const Region *reg, const Field &field, void *data, 768 size_t data_size) const = 0; 769 virtual int64_t put_field_internal(const NodeBlock *nb, const Field &field, void *data, 770 size_t data_size) const = 0; 771 virtual int64_t put_field_internal(const EdgeBlock *nb, const Field &field, void *data, 772 size_t data_size) const = 0; 773 virtual int64_t put_field_internal(const FaceBlock *nb, const Field &field, void *data, 774 size_t data_size) const = 0; 775 virtual int64_t put_field_internal(const ElementBlock *eb, const Field &field, void *data, 776 size_t data_size) const = 0; 777 virtual int64_t put_field_internal(const SideBlock *fb, const Field &field, void *data, 778 size_t data_size) const = 0; 779 virtual int64_t put_field_internal(const NodeSet *ns, const Field &field, void *data, 780 size_t data_size) const = 0; 781 virtual int64_t put_field_internal(const EdgeSet *ns, const Field &field, void *data, 782 size_t data_size) const = 0; 783 virtual int64_t put_field_internal(const FaceSet *ns, const Field &field, void *data, 784 size_t data_size) const = 0; 785 virtual int64_t put_field_internal(const ElementSet *ns, const Field &field, void *data, 786 size_t data_size) const = 0; 787 virtual int64_t put_field_internal(const SideSet *fs, const Field &field, void *data, 788 size_t data_size) const = 0; 789 virtual int64_t put_field_internal(const CommSet *cs, const Field &field, void *data, 790 size_t data_size) const = 0; 791 virtual int64_t put_field_internal(const Assembly * /*as*/, const Field & /*field*/, 792 void * /*data*/, size_t /*data_size*/) const = 0; 793 virtual int64_t put_field_internal(const Blob * /*bl*/, const Field & /*field*/, 794 void * /*data*/, size_t /*data_size*/) const = 0; 795 virtual int64_t put_field_internal(const StructuredBlock * /*sb*/, const Field & /*field*/, 796 void * /*data*/, size_t /*data_size*/) const = 0; 797 798 mutable std::map<std::string, AxisAlignedBoundingBox> elementBlockBoundingBoxes; 799 800 Ioss::ParallelUtils util_; // Encapsulate parallel and other utility functions. 801 #if defined(IOSS_THREADSAFE) 802 protected: 803 mutable std::mutex m_; 804 805 private: 806 #endif 807 Region *region_{nullptr}; 808 char fieldSeparator{'_'}; 809 bool enableFieldRecognition{true}; 810 bool isInput; 811 bool isParallelConsistent{ 812 true}; // True if application will make field data get/put calls parallel 813 // consistently. 814 // True is default and required for parallel-io databases. 815 // Even if false, metadata operations must be called by all processors 816 817 bool singleProcOnly; // True if history or heartbeat which is only written from proc 0... 818 bool doLogging{false}; // True if logging field input/output 819 bool useGenericCanonicalName{ 820 false}; // True if "block_id" is used as canonical name instead of the name 821 // given on the mesh file e.g. "fireset". Both names are still aliases. 822 bool ignoreDatabaseNames{false}; // True if "block_{id}" used as canonical name; ignore any 823 // names on database. 824 mutable bool blockAdjacenciesCalculated{false}; // True if the lazy creation of 825 // block adjacencies has been calculated. 826 827 bool m_timeStateInOut{false}; 828 bool m_enableTracing{false}; 829 std::chrono::time_point<std::chrono::steady_clock> 830 m_stateStart; // Used for optional output step timing. 831 }; 832 } // namespace Ioss 833 #endif 834