1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 
18 
19 
20 #ifndef LIBMESH_EXODUSII_IO_H
21 #define LIBMESH_EXODUSII_IO_H
22 
23 
24 // Local includes
25 #include "libmesh/libmesh_common.h"
26 #include "libmesh/mesh_input.h"
27 #include "libmesh/mesh_output.h"
28 #include "libmesh/parallel_object.h"
29 #include "libmesh/boundary_info.h" // BoundaryInfo::BCTuple
30 #include "libmesh/exodus_header_info.h"
31 
32 namespace libMesh
33 {
34 
35 // Forward declarations
36 class EquationSystems;
37 class ExodusII_IO_Helper;
38 class MeshBase;
39 class System;
40 
41 /**
42  * The \p ExodusII_IO class implements reading meshes in the
43  * \p ExodusII file format from Sandia National Labs.  By
44  * default, LibMesh expects ExodusII files to have a ".exd"
45  * or ".e" file extension.
46  *
47  * \author Benjamin Kirk
48  * \author John Peterson
49  * \date 2004
50  * \brief Handles reading and writing of Exodus binary files.
51  */
52 class ExodusII_IO : public MeshInput<MeshBase>,
53                     public MeshOutput<MeshBase>,
54                     public ParallelObject
55 {
56 public:
57 
58   /**
59    * Constructor.  Takes a writable reference to a mesh object.
60    * This is the constructor required to read a mesh.
61    */
62   explicit
63   ExodusII_IO (MeshBase & mesh,
64                bool single_precision=false);
65 
66   /**
67    * Destructor.
68    */
69   virtual ~ExodusII_IO ();
70 
71   /**
72    * This method implements reading a mesh from a specified file.
73    * Open the file named \p name and read the mesh in Sandia National Lab's
74    * ExodusII format. This is the method to use for reading in meshes generated
75    * by cubit.  Works in 2D for \p TRIs, \p TRI6s, \p QUAD s, and \p QUAD9s.
76    * Works in 3D for \p TET4s, \p TET10s, \p HEX8s, and \p HEX27s.
77    */
78   virtual void read (const std::string & name) override;
79 
80   /**
81    * Read only the header information, instead of the entire
82    * mesh. After the header is read, the file is closed and the
83    * MeshBase object remains unchanged. This capability is useful if
84    * you only need to know the mesh "metadata" and should be faster
85    * than reading in all the nodes and elems.
86    *
87    * The header information currently includes:
88    * .) Title string
89    * .) Mesh spatial dimension
90    * .) Number of nodes
91    * .) Number of elements
92    * .) Number of element blocks
93    * .) Number of node sets
94    * .) Number of side sets
95    * .) Number of edge blocks/edges
96    */
97   ExodusHeaderInfo read_header (const std::string & name);
98 
99   /**
100    * This method implements writing a mesh to a specified file.
101    */
102   virtual void write (const std::string & fname) override;
103 
104   /**
105    * Set the flag indicating if we should be verbose.
106    */
107   void verbose (bool set_verbosity);
108 
109   /**
110    * Set the flag indicating whether the complex modulus should be
111    * written when complex numbers are enabled. By default this flag
112    * is set to true.
113    */
114   void write_complex_magnitude (bool val);
115 
116   /**
117    * \returns An array containing the timesteps in the file.
118    */
119   const std::vector<Real> & get_time_steps();
120 
121   /**
122    * \returns The number of timesteps currently stored in the Exodus
123    * file.
124    *
125    * Knowing the number of time steps currently stored in the file is
126    * sometimes necessary when appending, so we can know where to start
127    * writing new data.  Throws an error if the file is not currently
128    * open for reading or writing.
129    */
130   int get_num_time_steps();
131 
132   /**
133    * If we read in a nodal solution while reading in a mesh, we can attempt
134    * to copy that nodal solution into an EquationSystems object.
135    */
136   void copy_nodal_solution(System & system,
137                            std::string system_var_name,
138                            std::string exodus_var_name,
139                            unsigned int timestep=1);
140 
141   /**
142    * If we read in a elemental solution while reading in a mesh, we can attempt
143    * to copy that elemental solution into an EquationSystems object.
144    */
145   void copy_elemental_solution(System & system,
146                                std::string system_var_name,
147                                std::string exodus_var_name,
148                                unsigned int timestep=1);
149 
150   /**
151    * Copy global variables into scalar variables of a System object.
152    */
153   void copy_scalar_solution(System & system,
154                             std::vector<std::string> system_var_names,
155                             std::vector<std::string> exodus_var_names,
156                             unsigned int timestep=1);
157 
158   /**
159    * Given an elemental variable and a time step, returns a mapping from the
160    * elements (top parent) unique IDs to the value of the elemental variable at
161    * the corresponding time step index.
162    * Note that this function MUST only be called before renumbering!
163    * This function is essentially a wrapper for read_elemental_var_values from
164    * the exodus helper (which is not accessible outside this class).
165    * \param elemental_var_name Name of an elemental variable
166    * \param timestep The corresponding time step index
167    * \param unique_id_to_value_map The map to be filled
168    */
169   void read_elemental_variable(std::string elemental_var_name,
170                                unsigned int timestep,
171                                std::map<unsigned int, Real> & unique_id_to_value_map);
172 
173   /**
174    * Given a vector of global variables and a time step, returns the values
175    * of the global variable at the corresponding time step index.
176    * \param global_var_names Vector of names of global variables
177    * \param timestep The corresponding time step index
178    * \param global_values The vector to be filled
179    */
180   void read_global_variable(std::vector<std::string> global_var_names,
181                             unsigned int timestep,
182                             std::vector<Real> & global_values);
183 
184   /**
185    * Writes a exodusII file with discontinuous data
186    */
187   void write_discontinuous_exodusII (const std::string & name,
188                                      const EquationSystems & es,
189                                      const std::set<std::string> * system_names=nullptr);
190 
191   /**
192    * Writes a discontinuous solution at a specific timestep
193    * \param fname Name of the file to be written
194    * \param es EquationSystems object which contains the solution vector
195    * \param timestep The timestep to write out. (should be _1_ indexed)
196    * \param time The current simulation time
197    * \param system_names Optional list of systems to write solutions for.
198    */
199   void write_timestep_discontinuous (const std::string &fname,
200                                      const EquationSystems &es,
201                                      const int timestep,
202                                      const Real time,
203                                      const std::set<std::string> * system_names=nullptr);
204 
205   /**
206    * Write out element solution.
207    */
208   void write_element_data (const EquationSystems & es);
209 
210   /**
211    * Similar to the function above, but instead of only handling
212    * (CONSTANT, MONOMIAL) data, writes out a general discontinuous
213    * solution field, e.g. (FIRST, L2_LAGRANGE) or (SECOND, MONOMIAL)
214    * as a number of elemental fields equal to the number of vertices in
215    * each element. For example, if you have a (FIRST, L2_LAGRANGE)
216    * variable "u" defined on HEX8 elements, calling this function
217    * would by default write 8 elemental fields named u_elem_node_0,
218    * u_elem_node_1, u_elem_node_2, etc.
219    *
220    * This may be useful if you have a viz tool which is capable of
221    * interpreting this element data as a discontinuous solution field.
222    * Note that (CONSTANT, MONOMIAL) data is still written as a single
223    * value per element, as it makes no sense to write n_vertices
224    * copies of the same value.
225    *
226    * The 'var_suffix' parameter, which defaults to "_elem_node_", is
227    * used to generate the elemental variable names, and is inserted
228    * between the base variable name and the node id which the variable
229    * applies to, e.g. "u_elem_node_0", "u_elem_node_1", etc.
230    */
231   void
232   write_element_data_from_discontinuous_nodal_data
233   (const EquationSystems & es,
234    const std::set<std::string> * system_names = nullptr,
235    const std::string & var_suffix = "_elem_node_");
236 
237   /**
238    * Bring in base class functionality for name resolution and to
239    * avoid warnings about hidden overloaded virtual functions.
240    */
241   using MeshOutput<MeshBase>::write_nodal_data;
242   using MeshOutput<MeshBase>::write_nodal_data_discontinuous;
243 
244   /**
245    * Write out a nodal solution.
246    */
247   virtual void write_nodal_data (const std::string &,
248                                  const std::vector<Number> &,
249                                  const std::vector<std::string> &) override;
250 
251   /**
252    * Write out a discontinuous nodal solution.
253    */
254   void write_nodal_data_discontinuous (const std::string &,
255                                        const std::vector<Number> &,
256                                        const std::vector<std::string> &) override;
257 
258   /**
259    * Write out global variables.
260    */
261   void write_global_data (const std::vector<Number> &,
262                           const std::vector<std::string> &);
263 
264   /**
265    * Write out information records.
266    */
267   void write_information_records (const std::vector<std::string> &);
268 
269   /**
270    * Writes out the solution at a specific timestep.
271    * \param fname Name of the file to write to
272    * \param es EquationSystems object which contains the solution vector.
273    * \param timestep The timestep to write out, should be _1_ indexed.
274    * \param time The current simulation time.
275    * \param system_names Optional list of systems to write solutions for.
276    */
277   void write_timestep (const std::string & fname,
278                        const EquationSystems & es,
279                        const int timestep,
280                        const Real time,
281                        const std::set<std::string> * system_names=nullptr);
282 
283   /**
284    * The Exodus format can also store values on sidesets. This can be
285    * thought of as an alternative to defining an elemental variable
286    * field on lower-dimensional elements making up a part of the
287    * boundary. The inputs to the function are:
288    * .) var_names[i] is the name of the ith sideset variable to be written to file.
289    * .) side_ids[i] is a set of side_ids where var_names[i] is active.
290    * .) bc_vals[i] is a map from (elem,side,id) BCTuple objects to the
291    *    corresponding real-valued data.
292    *
293    * \note You must have already written the mesh by calling
294    * e.g. write() before calling this function, because it uses the
295    * existing ordering of the Exodus sidesets.
296    */
297   void
298   write_sideset_data (int timestep,
299                       const std::vector<std::string> & var_names,
300                       const std::vector<std::set<boundary_id_type>> & side_ids,
301                       const std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals);
302 
303   /**
304    * Similar to write_sideset_data(), this function is used to read
305    * the data at a particular timestep. TODO: currently _all_ the
306    * sideset variables are read, but we might want to change this to
307    * only read the requested ones.
308    */
309   void
310   read_sideset_data (int timestep,
311                      std::vector<std::string> & var_names,
312                      std::vector<std::set<boundary_id_type>> & side_ids,
313                      std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals);
314 
315   /**
316    * Read all the nodeset data at a particular timestep. TODO:
317    * currently _all_ the nodeset variables are read, but we might want
318    * to change this to only read the requested ones.
319    */
320   void
321   read_nodeset_data (int timestep,
322                      std::vector<std::string> & var_names,
323                      std::vector<std::set<boundary_id_type>> & node_boundary_ids,
324                      std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals);
325 
326   /**
327    * Set the elemental variables in the Exodus file to be read into extra
328    * element integers. The names of these elemental variables will be used to
329    * name the extra element integers.
330    */
331   void set_extra_integer_vars(const std::vector<std::string> & extra_integer_vars);
332 
333   /**
334    * Sets the list of variable names to be included in the output.
335    * This is _optional_.  If this is never called then all variables
336    * will be present. If this is called and an empty vector is supplied
337    * no variables will be output. Setting the allow_empty = false will
338    * result in empty vectors supplied here to also be populated with all
339    * variables.
340    */
341   void set_output_variables(const std::vector<std::string> & output_variables,
342                             bool allow_empty = true);
343 
344   /**
345    * In the general case, meshes containing 2D elements can be
346    * manifolds living in 3D space, thus by default we write all
347    * meshes with the Exodus dimension set to LIBMESH_DIM =
348    * mesh.spatial_dimension().
349    *
350    * In certain cases, however, the user may know his 2D mesh actually
351    * lives in the z=0 plane, and therefore wants to write a truly 2D
352    * Exodus mesh.  In such a case, he should call this function with
353    * val=true.
354    */
355   void use_mesh_dimension_instead_of_spatial_dimension(bool val);
356 
357   /**
358    * Directly control the num_dim which is written to the Exodus file.
359    * If non-zero, this value supersedes all other dimensions, including:
360    * 1.) MeshBase::spatial_dimension()
361    * 2.) MeshBase::mesh_dimension()
362    * 3.) Any value passed to use_mesh_dimension_instead_of_spatial_dimension()
363    * This is useful/necessary for working around a bug in Paraview which
364    * prevents the "Plot Over Line" filter from working on 1D meshes.
365    */
366   void write_as_dimension(unsigned dim);
367 
368   /**
369    * Allows you to set a vector that is added to the coordinates of
370    * all of the nodes. Effectively, this "moves" the mesh to a
371    * particular position.
372    *
373    * \deprecated As requested by Roy in libmesh PR #90, this function
374    * was "deprecated on arrival". There is not really a suitable
375    * replacement for it in the works, however. The same effect *could*
376    * be achieved by calling MeshTools::Modification::translate()
377    * twice, but that approach seems inefficient in the case of very
378    * large problems with millions of nodes. That said, this should
379    * probably become a base class API so that it works for all the
380    * different IO subclasses.
381    */
382   void set_coordinate_offset(Point p);
383 
384   /**
385    * If true, this flag will cause the ExodusII_IO object to attempt to
386    * open an existing file for writing, rather than creating a new file.
387    * Obviously this will only work if the file already exists.
388    */
389   void append(bool val);
390 
391   /**
392    * Return list of the elemental variable names
393    */
394   const std::vector<std::string> & get_elem_var_names();
395 
396   /**
397    * Return list of the nodal variable names
398    */
399   const std::vector<std::string> & get_nodal_var_names();
400 
401   /**
402    * Return list of the global variable names
403    */
404   const std::vector<std::string> & get_global_var_names();
405 
406 #ifdef LIBMESH_HAVE_EXODUS_API
407   /**
408    * Return a reference to the ExodusII_IO_Helper object.
409    */
410   ExodusII_IO_Helper & get_exio_helper();
411 #endif
412 
413   /**
414    * This function factors out a bunch of code which is common to the
415    * write_nodal_data() and write_nodal_data_discontinuous() functions
416    */
417   void write_nodal_data_common(std::string fname,
418                                const std::vector<std::string> & names,
419                                bool continuous=true);
420 
421 private:
422   /**
423    * Only attempt to instantiate an ExodusII helper class
424    * if the Exodus API is defined.  This class will have no
425    * functionality when LIBMESH_HAVE_EXODUS_API is not defined.
426    */
427 #ifdef LIBMESH_HAVE_EXODUS_API
428   std::unique_ptr<ExodusII_IO_Helper> exio_helper;
429 
430   /**
431    * Stores the current value of the timestep when calling
432    * ExodusII_IO::write_timestep().
433    */
434   int _timestep;
435 
436   /**
437    * should we be verbose?
438    */
439   bool _verbose;
440 
441   /**
442    * Default false.  If true, files will be opened with EX_WRITE
443    * rather than created from scratch when writing.
444    */
445   bool _append;
446 #endif
447 
448   /**
449    * An optional list of variables in the EXODUS file that are
450    * to be used to set extra integers when loading the file into a mesh.
451    * The variable names will be used to name the extra integers.
452    */
453   std::vector<std::string> _extra_integer_vars;
454 
455   /**
456    * The names of the variables to be output.
457    * If this is empty then all variables are output.
458    */
459   std::vector<std::string> _output_variables;
460 
461   /**
462    * Flag which controls the behavior of _output_variables:
463    * .) If true, _output_variables is allowed to remain empty.
464    * .) If false, if _output_variables is empty it will be populated
465    *    with a complete list of all variables.
466    * .) By default, calling set_output_variables() sets this flag to
467    *    true, but it provides an override.
468    */
469   bool _allow_empty_variables;
470 
471   /**
472    * By default, when complex numbers are enabled, for each variable
473    * we write out three values: the real part, "r_u" the imaginary
474    * part, "i_u", and the complex modulus, a_u := sqrt(r_u*r_u +
475    * i_u*i_u), which is also the value returned by
476    * std::abs(std::complex).  Since the modulus is not an independent
477    * quantity, we can set this flag to false and save some file space
478    * by not writing out.
479    */
480   bool _write_complex_abs;
481 };
482 
483 
484 } // namespace libMesh
485 
486 
487 #endif // LIBMESH_EXODUSII_IO_H
488