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