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