libMesh
exodusII_io.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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 // C++ includes
20 #include <fstream>
21 #include <cstring>
22 #include <sstream>
23 #include <map>
24 
25 // Local includes
26 #include "libmesh/exodusII_io.h"
27 #include "libmesh/boundary_info.h"
28 #include "libmesh/mesh_base.h"
29 #include "libmesh/enum_elem_type.h"
30 #include "libmesh/elem.h"
31 #include "libmesh/equation_systems.h"
32 #include "libmesh/libmesh_logging.h"
33 #include "libmesh/system.h"
34 #include "libmesh/numeric_vector.h"
35 #include "libmesh/exodusII_io_helper.h"
36 #include "libmesh/enum_to_string.h"
37 #include "libmesh/mesh_communication.h"
38 #include "libmesh/parallel_mesh.h"
39 #include "libmesh/dof_map.h"
40 #include "libmesh/parallel.h"
41 #include "libmesh/utility.h"
42 #include "libmesh/auto_ptr.h" // libmesh_make_unique
43 
44 namespace libMesh
45 {
46 
47 // ------------------------------------------------------------
48 // ExodusII_IO class members
50 #ifdef LIBMESH_HAVE_EXODUS_API
51  bool single_precision
52 #else
53  bool
54 #endif
55  ) :
58  /* is_parallel_format = */ false,
59  /* serial_only_needed_on_proc_0 = */ true),
61 #ifdef LIBMESH_HAVE_EXODUS_API
62  exio_helper(libmesh_make_unique<ExodusII_IO_Helper>(*this, false, true, single_precision)),
63  _timestep(1),
64  _verbose(false),
65  _append(false),
66 #endif
67  _allow_empty_variables(false)
68 {
69 }
70 
71 
72 void ExodusII_IO::set_output_variables(const std::vector<std::string> & output_variables,
73  bool allow_empty)
74 {
75  _output_variables = output_variables;
76  _allow_empty_variables = allow_empty;
77 }
78 
79 
80 
81 #ifdef LIBMESH_ENABLE_DEPRECATED
83  std::string var_name,
84  unsigned int timestep)
85 {
86  libmesh_deprecated();
87  copy_nodal_solution(system, var_name, var_name, timestep);
88 }
89 #endif
90 
91 
92 
94  const EquationSystems & es,
95  const std::set<std::string> * system_names)
96 {
97  std::vector<std::string> solution_names;
98  std::vector<Number> v;
99 
100  es.build_variable_names (solution_names, nullptr, system_names);
101  es.build_discontinuous_solution_vector (v, system_names);
102  this->write_nodal_data_discontinuous(name, v, solution_names);
103 }
104 
105 
106 #ifdef LIBMESH_HAVE_EXODUS_API
107 void ExodusII_IO::write_timestep_discontinuous (const std::string &fname,
108  const EquationSystems &es,
109  const int timestep,
110  const Real time,
111  const std::set<std::string> * system_names)
112 {
113  _timestep = timestep;
114  write_discontinuous_equation_systems (fname,es,system_names);
115 
117  return;
118 
119  exio_helper->write_timestep(timestep, time);
120 }
121 
122 #else
123 void ExodusII_IO::write_timestep_discontinuous (const std::string & /* fname */,
124  const EquationSystems & /* es */,
125  const int /* timestep */,
126  const Real /* time */,
127  const std::set<std::string> * /*system_names*/)
128 { libmesh_error(); }
129 #endif
130 
131 
132 // ------------------------------------------------------------
133 // When the Exodus API is present...
134 #ifdef LIBMESH_HAVE_EXODUS_API
135 
137 {
138  exio_helper->close();
139 }
140 
141 
142 
143 void ExodusII_IO::read (const std::string & fname)
144 {
145  // Get a reference to the mesh we are reading
147 
148  // Clear any existing mesh data
149  mesh.clear();
150 
151  // Keep track of what kinds of elements this file contains
152  elems_of_dimension.clear();
153  elems_of_dimension.resize(4, false);
154 
155  // Open the exodus file in EX_READ mode
156  exio_helper->open(fname.c_str(), /*read_only=*/true);
157 
158  // Get header information from exodus file
159  exio_helper->read_header();
160 
161  // Read the QA records
162  exio_helper->read_qa_records();
163 
164  // Print header information
165  exio_helper->print_header();
166 
167  // Read nodes from the exodus file
168  exio_helper->read_nodes();
169 
170  // Reserve space for the nodes.
171  mesh.reserve_nodes(exio_helper->num_nodes);
172 
173  // Read the node number map from the Exodus file. This is
174  // required if we want to preserve the numbering of nodes as it
175  // exists in the Exodus file. If the Exodus file does not contain
176  // a node_num_map, the identity map is returned by this call.
177  exio_helper->read_node_num_map();
178 
179  // Loop over the nodes, create Nodes with local processor_id 0.
180  for (int i=0; i<exio_helper->num_nodes; i++)
181  {
182  // Use the node_num_map to get the correct ID for Exodus
183  int exodus_id = exio_helper->node_num_map[i];
184 
185  // Catch the node that was added to the mesh
186  Node * added_node = mesh.add_point (Point(exio_helper->x[i], exio_helper->y[i], exio_helper->z[i]), exodus_id-1);
187 
188  // If the Mesh assigned an ID different from what is in the
189  // Exodus file, we should probably error.
190  if (added_node->id() != static_cast<unsigned>(exodus_id-1))
191  libmesh_error_msg("Error! Mesh assigned node ID " \
192  << added_node->id() \
193  << " which is different from the (zero-based) Exodus ID " \
194  << exodus_id-1 \
195  << "!");
196  }
197 
198  // This assert is no longer valid if the nodes are not numbered
199  // sequentially starting from 1 in the Exodus file.
200  // libmesh_assert_equal_to (static_cast<unsigned int>(exio_helper->num_nodes), mesh.n_nodes());
201 
202  // Get information about all the element and edge blocks
203  exio_helper->read_block_info();
204 
205  // Reserve space for the elements
206  mesh.reserve_elem(exio_helper->num_elem);
207 
208  // Read the element number map from the Exodus file. This is
209  // required if we want to preserve the numbering of elements as it
210  // exists in the Exodus file. If the Exodus file does not contain
211  // an elem_num_map, the identity map is returned by this call.
212  exio_helper->read_elem_num_map();
213 
214  // Read in the element connectivity for each block.
215  int nelem_last_block = 0;
216 
217  // Loop over all the element blocks
218  for (int i=0; i<exio_helper->num_elem_blk; i++)
219  {
220  // Read the information for block i
221  exio_helper->read_elem_in_block (i);
222  int subdomain_id = exio_helper->get_block_id(i);
223 
224  // populate the map of names
225  std::string subdomain_name = exio_helper->get_block_name(i);
226  if (!subdomain_name.empty())
227  mesh.subdomain_name(static_cast<subdomain_id_type>(subdomain_id)) = subdomain_name;
228 
229  // Set any relevant node/edge maps for this element
230  const std::string type_str (exio_helper->get_elem_type());
231  const auto & conv = exio_helper->get_conversion(type_str);
232 
233  // Loop over all the faces in this block
234  int jmax = nelem_last_block+exio_helper->num_elem_this_blk;
235  for (int j=nelem_last_block; j<jmax; j++)
236  {
237  Elem * elem = Elem::build (conv.libmesh_elem_type()).release();
238  libmesh_assert (elem);
239  elem->subdomain_id() = static_cast<subdomain_id_type>(subdomain_id) ;
240 
241  // Use the elem_num_map to obtain the ID of this element in the Exodus file
242  int exodus_id = exio_helper->elem_num_map[j];
243 
244  // Assign this element the same ID it had in the Exodus
245  // file, but make it zero-based by subtracting 1. Note:
246  // some day we could use 1-based numbering in libmesh and
247  // thus match the Exodus numbering exactly, but at the
248  // moment libmesh is zero-based.
249  elem->set_id(exodus_id-1);
250 
251  // Record that we have seen an element of dimension elem->dim()
252  elems_of_dimension[elem->dim()] = true;
253 
254  // Catch the Elem pointer that the Mesh throws back
255  elem = mesh.add_elem (elem);
256 
257  // If the Mesh assigned an ID different from what is in the
258  // Exodus file, we should probably error.
259  if (elem->id() != static_cast<unsigned>(exodus_id-1))
260  libmesh_error_msg("Error! Mesh assigned ID " \
261  << elem->id() \
262  << " which is different from the (zero-based) Exodus ID " \
263  << exodus_id-1 \
264  << "!");
265 
266  // Set all the nodes for this element
267  for (int k=0; k<exio_helper->num_nodes_per_elem; k++)
268  {
269  // global index
270  int gi = (j-nelem_last_block)*exio_helper->num_nodes_per_elem + conv.get_node_map(k);
271 
272  // The entries in 'connect' are actually (1-based)
273  // indices into the node_num_map, so to get the right
274  // node ID we:
275  // 1.) Subtract 1 from connect[gi]
276  // 2.) Pass it through node_num_map to get the corresponding Exodus ID
277  // 3.) Subtract 1 from that, since libmesh node numbering is "zero"-based,
278  // even when the Exodus node numbering doesn't start with 1.
279  int libmesh_node_id = exio_helper->node_num_map[exio_helper->connect[gi] - 1] - 1;
280 
281  // Set the node pointer in the Elem
282  elem->set_node(k) = mesh.node_ptr(libmesh_node_id);
283  }
284  }
285 
286  // running sum of # of elements per block,
287  // (should equal total number of elements in the end)
288  nelem_last_block += exio_helper->num_elem_this_blk;
289  }
290 
291  // Read in edge blocks, storing information in the BoundaryInfo object.
292  // Edge blocks are treated as BCs.
293  exio_helper->read_edge_blocks(mesh);
294 
295  // Set the mesh dimension to the largest encountered for an element
296  for (unsigned char i=0; i!=4; ++i)
297  if (elems_of_dimension[i])
299 
300  // Read in sideset information -- this is useful for applying boundary conditions
301  {
302  // Get basic information about all sidesets
303  exio_helper->read_sideset_info();
304  int offset=0;
305  for (int i=0; i<exio_helper->num_side_sets; i++)
306  {
307  // Compute new offset
308  offset += (i > 0 ? exio_helper->num_sides_per_set[i-1] : 0);
309  exio_helper->read_sideset (i, offset);
310 
311  std::string sideset_name = exio_helper->get_side_set_name(i);
312  if (!sideset_name.empty())
314  (cast_int<boundary_id_type>(exio_helper->get_side_set_id(i)))
315  = sideset_name;
316  }
317 
318  for (auto e : index_range(exio_helper->elem_list))
319  {
320  // The numbers in the Exodus file sidesets should be thought
321  // of as (1-based) indices into the elem_num_map array. So,
322  // to get the right element ID we have to:
323  // 1.) Subtract 1 from elem_list[e] (to get a zero-based index)
324  // 2.) Pass it through elem_num_map (to get the corresponding Exodus ID)
325  // 3.) Subtract 1 from that, since libmesh is "zero"-based,
326  // even when the Exodus numbering doesn't start with 1.
327  dof_id_type libmesh_elem_id =
328  cast_int<dof_id_type>(exio_helper->elem_num_map[exio_helper->elem_list[e] - 1] - 1);
329 
330  // Set any relevant node/edge maps for this element
331  Elem & elem = mesh.elem_ref(libmesh_elem_id);
332 
333  const auto & conv = exio_helper->get_conversion(elem.type());
334 
335  // Map the zero-based Exodus side numbering to the libmesh side numbering
336  unsigned int raw_side_index = exio_helper->side_list[e]-1;
337  std::size_t side_index_offset = conv.get_shellface_index_offset();
338 
339  if (raw_side_index < side_index_offset)
340  {
341  // We assume this is a "shell face"
342  int mapped_shellface = raw_side_index;
343 
344  // Check for errors
345  if (mapped_shellface == ExodusII_IO_Helper::Conversion::invalid_id)
346  libmesh_error_msg("Invalid 1-based side id: " \
347  << mapped_shellface \
348  << " detected for " \
349  << Utility::enum_to_string(elem.type()));
350 
351  // Add this (elem,shellface,id) triplet to the BoundaryInfo object.
352  mesh.get_boundary_info().add_shellface (libmesh_elem_id,
353  cast_int<unsigned short>(mapped_shellface),
354  cast_int<boundary_id_type>(exio_helper->id_list[e]));
355  }
356  else
357  {
358  unsigned int side_index = static_cast<unsigned int>(raw_side_index - side_index_offset);
359  int mapped_side = conv.get_side_map(side_index);
360 
361  // Check for errors
363  libmesh_error_msg("Invalid 1-based side id: " \
364  << side_index \
365  << " detected for " \
366  << Utility::enum_to_string(elem.type()));
367 
368  // Add this (elem,side,id) triplet to the BoundaryInfo object.
369  mesh.get_boundary_info().add_side (libmesh_elem_id,
370  cast_int<unsigned short>(mapped_side),
371  cast_int<boundary_id_type>(exio_helper->id_list[e]));
372  }
373  } // end for (elem_list)
374  } // end read sideset info
375 
376  // Read nodeset info
377  {
378  // This fills in the following fields of the helper for later use:
379  // nodeset_ids
380  // num_nodes_per_set
381  // num_node_df_per_set
382  // node_sets_node_index
383  // node_sets_dist_index
384  // node_sets_node_list
385  // node_sets_dist_fact
386  exio_helper->read_all_nodesets();
387 
388  for (int nodeset=0; nodeset<exio_helper->num_node_sets; nodeset++)
389  {
390  boundary_id_type nodeset_id =
391  cast_int<boundary_id_type>(exio_helper->nodeset_ids[nodeset]);
392 
393  std::string nodeset_name = exio_helper->get_node_set_name(nodeset);
394  if (!nodeset_name.empty())
395  mesh.get_boundary_info().nodeset_name(nodeset_id) = nodeset_name;
396 
397  // Get starting index of node ids for current nodeset.
398  unsigned int offset = exio_helper->node_sets_node_index[nodeset];
399 
400  for (int i=0; i<exio_helper->num_nodes_per_set[nodeset]; ++i)
401  {
402  int exodus_id = exio_helper->node_sets_node_list[i + offset];
403 
404  // It's possible for nodesets to have invalid ids in them
405  // by accident. Instead of possibly accessing past the
406  // end of node_num_map, let's make sure we have that many
407  // entries.
408  if (static_cast<std::size_t>(exodus_id - 1) >= exio_helper->node_num_map.size())
409  libmesh_error_msg("Invalid Exodus node id " << exodus_id
410  << " found in nodeset " << nodeset_id);
411 
412  // As before, the entries in 'node_list' are 1-based
413  // indices into the node_num_map array, so we have to map
414  // them. See comment above.
415  int libmesh_node_id = exio_helper->node_num_map[exodus_id - 1] - 1;
416  mesh.get_boundary_info().add_node(cast_int<dof_id_type>(libmesh_node_id),
417  nodeset_id);
418  }
419  }
420  }
421 
422 #if LIBMESH_DIM < 3
423  if (mesh.mesh_dimension() > LIBMESH_DIM)
424  libmesh_error_msg("Cannot open dimension " \
425  << mesh.mesh_dimension() \
426  << " mesh file when configured without " \
427  << mesh.mesh_dimension() \
428  << "D support.");
429 #endif
430 }
431 
432 
433 
434 void ExodusII_IO::verbose (bool set_verbosity)
435 {
436  _verbose = set_verbosity;
437 
438  // Set the verbose flag in the helper object as well.
439  exio_helper->verbose = _verbose;
440 }
441 
442 
443 
445 {
446  exio_helper->use_mesh_dimension_instead_of_spatial_dimension(val);
447 }
448 
449 
450 
452 {
453  exio_helper->write_as_dimension(dim);
454 }
455 
456 
457 
459 {
460  libmesh_warning("This method may be deprecated in the future");
461  exio_helper->set_coordinate_offset(p);
462 }
463 
464 
465 
466 void ExodusII_IO::append(bool val)
467 {
468  _append = val;
469 }
470 
471 
472 
473 const std::vector<Real> & ExodusII_IO::get_time_steps()
474 {
475  if (!exio_helper->opened_for_reading)
476  libmesh_error_msg("ERROR, ExodusII file must be opened for reading before calling ExodusII_IO::get_time_steps()!");
477 
478  exio_helper->read_time_steps();
479  return exio_helper->time_steps;
480 }
481 
482 
483 
485 {
486  if (!exio_helper->opened_for_reading && !exio_helper->opened_for_writing)
487  libmesh_error_msg("ERROR, ExodusII file must be opened for reading or writing before calling ExodusII_IO::get_num_time_steps()!");
488 
489  exio_helper->read_num_time_steps();
490  return exio_helper->num_time_steps;
491 }
492 
493 
494 
496  std::string system_var_name,
497  std::string exodus_var_name,
498  unsigned int timestep)
499 {
500  if (!exio_helper->opened_for_reading)
501  libmesh_error_msg("ERROR, ExodusII file must be opened for reading before copying a nodal solution!");
502 
503  exio_helper->read_nodal_var_values(exodus_var_name, timestep);
504 
505  const unsigned int var_num = system.variable_number(system_var_name);
506 
507  for (dof_id_type i=0,
508  n_nodal = cast_int<dof_id_type>(exio_helper->nodal_var_values.size());
509  i != n_nodal; ++i)
510  {
511  const Node * node = MeshInput<MeshBase>::mesh().query_node_ptr(i);
512 
513  if (node && node->n_comp(system.number(), var_num) > 0)
514  {
515  dof_id_type dof_index = node->dof_number(system.number(), var_num, 0);
516 
517  // If the dof_index is local to this processor, set the value
518  if ((dof_index >= system.solution->first_local_index()) && (dof_index < system.solution->last_local_index()))
519  system.solution->set (dof_index, exio_helper->nodal_var_values[i]);
520  }
521  }
522 
523  system.solution->close();
524  system.update();
525 }
526 
527 
528 
530  std::string system_var_name,
531  std::string exodus_var_name,
532  unsigned int timestep)
533 {
534  if (system.comm().rank() == 0)
535  {
536  if (!exio_helper->opened_for_reading)
537  libmesh_error_msg("ERROR, ExodusII file must be opened for reading before copying an elemental solution!");
538 
539  // Map from element ID to elemental variable value. We need to use
540  // a map here rather than a vector (e.g. elem_var_values) since the
541  // libmesh element numbering can contain "holes". This is the case
542  // if we are reading elemental var values from an adaptively refined
543  // mesh that has not been sequentially renumbered.
544  std::map<dof_id_type, Real> elem_var_value_map;
545  exio_helper->read_elemental_var_values(exodus_var_name, timestep, elem_var_value_map);
546 
547  const unsigned int var_num = system.variable_number(system_var_name);
548  if (system.variable_type(var_num) != FEType(CONSTANT, MONOMIAL))
549  libmesh_error_msg("Error! Trying to copy elemental solution into a variable that is not of CONSTANT MONOMIAL type.");
550 
551  std::map<dof_id_type, Real>::iterator
552  it = elem_var_value_map.begin(),
553  end = elem_var_value_map.end();
554 
555  for (; it!=end; ++it)
556  {
557  const Elem * elem = MeshInput<MeshBase>::mesh().query_elem_ptr(it->first);
558 
559  if (elem && elem->n_comp(system.number(), var_num) > 0)
560  {
561  dof_id_type dof_index = elem->dof_number(system.number(), var_num, 0);
562  system.solution->set (dof_index, it->second);
563  }
564  }
565  }
566 
567  system.solution->close();
568  system.update();
569 }
570 
572  std::vector<std::string> system_var_names,
573  std::vector<std::string> exodus_var_names,
574  unsigned int timestep)
575 {
576  if (!exio_helper->opened_for_reading)
577  libmesh_error_msg("ERROR, ExodusII file must be opened for reading before copying a scalar solution!");
578 
579  if (system_var_names.size() != exodus_var_names.size())
580  libmesh_error_msg("ERROR, the number of system_var_names must match exodus_var_names.");
581 
582  std::vector<Real> values_from_exodus;
583  read_global_variable(exodus_var_names, timestep, values_from_exodus);
584 
585 #ifdef LIBMESH_HAVE_MPI
586  if (this->n_processors() > 1)
587  {
588  const Parallel::MessageTag tag(1);
589  if (this->processor_id() == this->n_processors()-1)
590  this->comm().receive(0, values_from_exodus, tag);
591  if (this->processor_id() == 0)
592  this->comm().send(this->n_processors()-1, values_from_exodus, tag);
593  }
594 #endif
595 
596  if (system.processor_id() == (system.n_processors()-1))
597  {
598  const DofMap & dof_map = system.get_dof_map();
599 
600  for (auto i : index_range(system_var_names))
601  {
602  const unsigned int var_num = system.variable_scalar_number(system_var_names[i], 0);
603 
604  std::vector<dof_id_type> SCALAR_dofs;
605  dof_map.SCALAR_dof_indices(SCALAR_dofs, var_num);
606 
607  system.solution->set (SCALAR_dofs[0], values_from_exodus[i]);
608  }
609  }
610 
611  system.solution->close();
612  system.update();
613 }
614 
615 void ExodusII_IO::read_elemental_variable(std::string elemental_var_name,
616  unsigned int timestep,
617  std::map<unsigned int, Real> & unique_id_to_value_map)
618 {
619  // Note that this function MUST be called before renumbering
620  std::map<dof_id_type, Real> elem_var_value_map;
621 
622  exio_helper->read_elemental_var_values(elemental_var_name, timestep, elem_var_value_map);
623  for (auto & pr : elem_var_value_map)
624  {
625  const Elem * elem = MeshInput<MeshBase>::mesh().query_elem_ptr(pr.first);
626  unique_id_to_value_map.insert(std::make_pair(elem->top_parent()->unique_id(), pr.second));
627  }
628 }
629 
630 void ExodusII_IO::read_global_variable(std::vector<std::string> global_var_names,
631  unsigned int timestep,
632  std::vector<Real> & global_values)
633 {
634  std::size_t size = global_var_names.size();
635  if (size == 0)
636  libmesh_error_msg("ERROR, empty list of global variables to read from the Exodus file.");
637 
638  // read the values for all global variables
639  std::vector<Real> values_from_exodus;
640  exio_helper->read_var_names(ExodusII_IO_Helper::GLOBAL);
641  exio_helper->read_global_values(values_from_exodus, timestep);
642  std::vector<std::string> global_var_names_exodus = exio_helper->global_var_names;
643 
644  if (values_from_exodus.size() == 0)
645  return; // This will happen in parallel on procs that are not 0
646 
647  global_values.clear();
648  for (std::size_t i = 0; i != size; ++i)
649  {
650  // for each global variable in global_var_names, look the corresponding one in global_var_names_from_exodus
651  // and fill global_values accordingly
652  auto it = find(global_var_names_exodus.begin(), global_var_names_exodus.end(), global_var_names[i]);
653  if (it != global_var_names_exodus.end())
654  global_values.push_back(values_from_exodus[it - global_var_names_exodus.begin()]);
655  else
656  libmesh_error_msg("ERROR, Global variable " << global_var_names[i] << \
657  " not found in Exodus file.");
658  }
659 
660 }
661 
663 {
664  // Be sure the file has been opened for writing!
665  if (MeshOutput<MeshBase>::mesh().processor_id() == 0 && !exio_helper->opened_for_writing)
666  libmesh_error_msg("ERROR, ExodusII file must be initialized before outputting element variables.");
667 
668  // This function currently only works on serialized meshes. We rely
669  // on having a reference to a non-const MeshBase object from our
670  // MeshInput parent class to construct a MeshSerializer object,
671  // similar to what is done in ExodusII_IO::write(). Note that
672  // calling ExodusII_IO::write_timestep() followed by
673  // ExodusII_IO::write_element_data() when the underlying Mesh is a
674  // DistributedMesh will result in an unnecessary additional
675  // serialization/re-parallelization step.
676  // The "true" specifies that we only need the mesh serialized to processor 0
678 
679  // To be (possibly) filled with a filtered list of variable names to output.
680  std::vector<std::string> names;
681 
682  // If _output_variables is populated, only output the monomials which are
683  // also in the _output_variables vector.
684  if (_output_variables.size() > 0)
685  {
686  std::vector<std::string> monomials;
687  const FEType type(CONSTANT, MONOMIAL);
688 
689  // Create a list of monomial variable names
690  es.build_variable_names(monomials, &type);
691 
692  // Filter that list against the _output_variables list. Note: if names is still empty after
693  // all this filtering, all the monomial variables will be gathered
694  for (const auto & var : monomials)
695  if (std::find(_output_variables.begin(), _output_variables.end(), var) != _output_variables.end())
696  names.push_back(var);
697  }
698 
699  // If we pass in a list of names to "build_elemental_solution_vector()"
700  // it'll filter the variables coming back.
701  std::vector<Number> soln;
702  es.build_elemental_solution_vector(soln, names);
703 
704  // Also, store the list of subdomains on which each variable is active
705  std::vector<std::set<subdomain_id_type>> vars_active_subdomains;
706  es.get_vars_active_subdomains(names, vars_active_subdomains);
707 
708  if (soln.empty()) // If there is nothing to write just return
709  return;
710 
711  // The data must ultimately be written block by block. This means that this data
712  // must be sorted appropriately.
713  if (MeshOutput<MeshBase>::mesh().processor_id())
714  return;
715 
717 
718 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
719 
720  std::vector<std::string> complex_names = exio_helper->get_complex_names(names);
721 
722  std::vector<std::set<subdomain_id_type>> complex_vars_active_subdomains =
723  exio_helper->get_complex_vars_active_subdomains(vars_active_subdomains);
724  exio_helper->initialize_element_variables(complex_names, complex_vars_active_subdomains);
725 
726  unsigned int num_values = soln.size();
727  unsigned int num_vars = names.size();
728  unsigned int num_elems = num_values / num_vars;
729 
730  // This will contain the real and imaginary parts and the magnitude
731  // of the values in soln
732  std::vector<Real> complex_soln(3*num_values);
733 
734  for (unsigned i=0; i<num_vars; ++i)
735  {
736 
737  for (unsigned int j=0; j<num_elems; ++j)
738  {
739  Number value = soln[i*num_vars + j];
740  complex_soln[3*i*num_elems + j] = value.real();
741  }
742  for (unsigned int j=0; j<num_elems; ++j)
743  {
744  Number value = soln[i*num_vars + j];
745  complex_soln[3*i*num_elems + num_elems +j] = value.imag();
746  }
747  for (unsigned int j=0; j<num_elems; ++j)
748  {
749  Number value = soln[i*num_vars + j];
750  complex_soln[3*i*num_elems + 2*num_elems + j] = std::abs(value);
751  }
752  }
753 
754  exio_helper->write_element_values(mesh, complex_soln, _timestep, complex_vars_active_subdomains);
755 
756 #else
757  exio_helper->initialize_element_variables(names, vars_active_subdomains);
758  exio_helper->write_element_values(mesh, soln, _timestep, vars_active_subdomains);
759 #endif
760 }
761 
762 
763 
764 void
766 (const EquationSystems & es,
767  const std::set<std::string> * system_names,
768  const std::string & var_suffix)
769 {
770  // Be sure that some other function has already opened the file and prepared it
771  // for writing. This is the same behavior as the write_element_data() function
772  // which we are trying to mimic.
773  if (MeshOutput<MeshBase>::mesh().processor_id() == 0 && !exio_helper->opened_for_writing)
774  libmesh_error_msg("ERROR, ExodusII file must be initialized before outputting element variables.");
775 
776  // This function currently only works on serialized meshes. The
777  // "true" flag specifies that we only need the mesh serialized to
778  // processor 0
781  true);
782 
783  // Note: in general we want to respect the contents of
784  // _output_variables, only building a solution vector with values
785  // from the requested variables. First build a list of all variable
786  // names, then throw out ones that aren't in _output_variables, if
787  // any.
788  std::vector<std::string> var_names;
789  es.build_variable_names (var_names, /*fetype=*/nullptr, system_names);
790 
791  // Get a subset of all variable names that are CONSTANT,
792  // MONOMIALs. We treat those slightly differently since they can
793  // truly only have a single value per Elem.
794  std::vector<std::string> monomial_var_names;
795  const FEType fe_type(CONSTANT, MONOMIAL);
796  es.build_variable_names(monomial_var_names, &fe_type);
797 
798  // Remove all names from var_names that are not in _output_variables.
799  // Note: This approach avoids errors when the user provides invalid
800  // variable names in _output_variables, as the code will not try to
801  // write a variable that doesn't exist.
802  if (!_output_variables.empty())
803  {
804  var_names.erase
805  (std::remove_if
806  (var_names.begin(),
807  var_names.end(),
808  [this](const std::string & name)
809  {return !std::count(_output_variables.begin(),
810  _output_variables.end(),
811  name);}),
812  var_names.end());
813 
814  // Also filter the monomial variable names.
815  monomial_var_names.erase
816  (std::remove_if
817  (monomial_var_names.begin(),
818  monomial_var_names.end(),
819  [this](const std::string & name)
820  {return !std::count(_output_variables.begin(),
821  _output_variables.end(),
822  name);}),
823  monomial_var_names.end());
824  }
825 
826  // Build a solution vector, limiting the results to the variables in
827  // var_names and the Systems in system_names, and only computing values
828  // at the vertices.
829  std::vector<Number> v;
831  (v, system_names, &var_names, /*vertices_only=*/true);
832 
833  // Get active subdomains for each variable in var_names.
834  std::vector<std::set<subdomain_id_type>> vars_active_subdomains;
835  es.get_vars_active_subdomains(var_names, vars_active_subdomains);
836 
837  // Determine names of variables to write based on the number of
838  // nodes/vertices the elements in different subdomains have.
840  std::map<subdomain_id_type, unsigned int> subdomain_id_to_vertices_per_elem;
841  for (const auto & elem : mesh.active_element_ptr_range())
842  {
843  // Try to insert key/value pair into the map. If this returns
844  // false, check the returned iterator's value to make sure it
845  // matches. It shouldn't actually be possible for this to fail
846  // (since if the Mesh was like this it would have already
847  // failed) but it doesn't hurt to be on the safe side.
848  auto pr2 = subdomain_id_to_vertices_per_elem.insert
849  (std::make_pair(elem->subdomain_id(), elem->n_vertices()));
850  if (!pr2.second && pr2.first->second != elem->n_vertices())
851  libmesh_error_msg("Elem with different number of vertices found.");
852  }
853 
854  // Determine "derived" variable names. These names are created by
855  // starting with the base variable name and appending the user's
856  // variable_suffix (default: "_elem_node_") followed by a node id.
857  //
858  // Not every derived variable will be active on every subdomain,
859  // even if the original variable _is_ active. Subdomains can have
860  // different geometric element types (with differing numbers of
861  // nodes), so some of the derived variable names will be inactive on
862  // those subdomains.
863  //
864  // Since we would otherwise generate the same name once per
865  // subdomain, we keep the list of names unique as we are creating
866  // it. We can't use a std::set for this because we don't want the
867  // variables names to be in a different order from the order
868  // they were written in the call to: build_discontinuous_solution_vector()
869  //
870  // The list of derived variable names includes one for each vertex,
871  // for higher-order elements we currently only write out vertex
872  // values, but this could be changed in the future without too much
873  // trouble.
874  std::vector<std::string> derived_var_names;
875 
876  // Keep track of mapping from derived_name to (orig_name, node_id)
877  // pair. We will use this later to determine whether a given
878  // variable is active on a given subdomain.
879  std::map<std::string, std::pair<std::string, unsigned int>>
880  derived_name_to_orig_name_and_node_id;
881 
882  for (const auto & pr : subdomain_id_to_vertices_per_elem)
883  {
884  const subdomain_id_type sbd_id = pr.first;
885  const unsigned int vertices_per_elem =
886  subdomain_id_to_vertices_per_elem[sbd_id];
887 
888  std::ostringstream oss;
889  for (unsigned int n=0; n<vertices_per_elem; ++n)
890  for (const auto & orig_var_name : var_names)
891  {
892  oss.str("");
893  oss.clear();
894  oss << orig_var_name << var_suffix << n;
895  std::string derived_name = oss.str();
896 
897  // Only add this var name if it's not already in the list.
898  if (!std::count(derived_var_names.begin(), derived_var_names.end(), derived_name))
899  {
900  derived_var_names.push_back(derived_name);
901  // Add entry for derived_name -> (orig_name, node_id) mapping.
902  derived_name_to_orig_name_and_node_id[derived_name] =
903  std::make_pair(orig_var_name, n);
904  }
905  }
906  }
907 
908  // For each derived variable name, determine whether it is active
909  // based on how many nodes/vertices the elements in a given subdomain have,
910  // and whether they were active on the subdomain to begin with.
911  std::vector<std::set<subdomain_id_type>>
912  derived_vars_active_subdomains(derived_var_names.size());
913 
914  // A new data structure for keeping track of a list of variable names
915  // that are in the discontinous solution vector on each subdomain. Used
916  // for indexing. Note: if a variable was inactive at the System level,
917  // an entry for it will still be in the discontinuous solution vector,
918  // but it will just have a value of zero. On the other hand, when we
919  // create the derived variable names some of them are "inactive" on
920  // different subdomains in the sense that they don't exist at all, i.e.
921  // there is no zero padding for them. We need to be able to distinguish
922  // between these two types in order to do the indexing into this vector
923  // correctly.
924  std::map<subdomain_id_type, std::vector<std::string>>
925  subdomain_to_var_names;
926 
927  for (auto derived_var_id : index_range(derived_var_names))
928  {
929  const auto & derived_name = derived_var_names[derived_var_id];
930  const auto & name_and_id =
931  libmesh_map_find (derived_name_to_orig_name_and_node_id,
932  derived_name);
933 
934  // Convenience variables for the map entry's contents.
935  const std::string & orig_name = name_and_id.first;
936  const unsigned int node_id = name_and_id.second;
937 
938  // For each subdomain, determine whether the current variable
939  // should be active on that subdomain.
940  for (const auto & pr : subdomain_id_to_vertices_per_elem)
941  {
942  // Convenience variables for the current subdomain and the
943  // number of nodes elements in this subdomain have.
944  subdomain_id_type sbd_id = pr.first;
945  unsigned int vertices_per_elem_this_sbd =
946  subdomain_id_to_vertices_per_elem[sbd_id];
947 
948  // Check whether variable orig_name was active on this
949  // subdomain to begin with by looking in the
950  // vars_active_subdomains container. We assume that the
951  // location of orig_name in the var_names vector matches its
952  // index in the vars_active_subdomains container.
953  auto var_loc = std::find(var_names.begin(), var_names.end(), orig_name);
954  if (var_loc == var_names.end())
955  libmesh_error_msg("Variable " << orig_name << " somehow not found in var_names array.");
956  auto var_id = std::distance(var_names.begin(), var_loc);
957 
958  // The derived_var will only be active if this subdomain has
959  // enough vertices for that to be the case.
960  if (node_id < vertices_per_elem_this_sbd)
961  {
962  // Regardless of whether the original variable was not active on this subdomain,
963  // the discontinuous solution vector will have zero padding for it, and
964  // we will need to account for it. Therefore it should still be added to
965  // the subdomain_to_var_names data structure!
966  subdomain_to_var_names[sbd_id].push_back(derived_name);
967 
968  // If the original variable was not active on the
969  // current subdomain, it should not be added to the
970  // derived_vars_active_subdomains data structure, since
971  // it will not be written to the Exodus file.
972 
973  // Determine if the original variable was active on the
974  // current subdomain.
975  bool orig_var_active =
976  (vars_active_subdomains[var_id].empty() ||
977  vars_active_subdomains[var_id].count(sbd_id));
978 
979  // And only if it was, add it to the
980  // derived_vars_active_subdomains data structure.
981  if (orig_var_active)
982  derived_vars_active_subdomains[derived_var_id].insert(sbd_id);
983  }
984  } // end loop over subdomain_id_to_vertices_per_elem
985  } // end loop over derived_var_names
986 
987  // At this point we've built the "true" list of derived names, but
988  // if there are any CONSTANT MONOMIALS in this list, we now want to
989  // remove all but one copy of them from the derived_var_names list,
990  // and rename them in (but not remove them from) the
991  // subdomain_to_var_names list, and then update the
992  // derived_vars_active_subdomains containers before finally calling
993  // the Exodus helper functions.
994  for (auto & derived_var_name : derived_var_names)
995  {
996  // Get the original name associated with this derived name.
997  const auto & name_and_id =
998  libmesh_map_find (derived_name_to_orig_name_and_node_id,
999  derived_var_name);
1000 
1001  // Convenience variables for the map entry's contents.
1002  const std::string & orig_name = name_and_id.first;
1003 
1004  // Was the original name a constant monomial?
1005  if (std::count(monomial_var_names.begin(),
1006  monomial_var_names.end(),
1007  orig_name))
1008  {
1009  // Rename this variable in the subdomain_to_var_names vectors.
1010  for (auto & pr : subdomain_to_var_names)
1011  {
1012  // Reference to ordered list of variable names on this subdomain.
1013  auto & name_vec = pr.second;
1014 
1015  auto name_vec_it =
1016  std::find(name_vec.begin(),
1017  name_vec.end(),
1018  derived_var_name);
1019 
1020  if (name_vec_it != name_vec.end())
1021  {
1022  // Actually rename it back to the orig_name, dropping
1023  // the "_elem_corner_" stuff.
1024  *name_vec_it = orig_name;
1025  }
1026  }
1027 
1028  // Finally, rename the variable in the derived_var_names vector itself.
1029  derived_var_name = orig_name;
1030  } // if (monomial)
1031  } // end loop over derived names
1032 
1033  // Now remove duplicate entries from derived_var_names after the first.
1034  // Also update the derived_vars_active_subdomains container in a consistent way.
1035  {
1036  std::vector<std::string> derived_var_names_edited;
1037  std::vector<std::set<subdomain_id_type>> derived_vars_active_subdomains_edited;
1038  std::vector<unsigned int> found_first(monomial_var_names.size());
1039 
1040  for (auto i : index_range(derived_var_names))
1041  {
1042  const auto & derived_var_name = derived_var_names[i];
1043  const auto & active_set = derived_vars_active_subdomains[i];
1044 
1045  // Determine whether we will keep this derived variable name in
1046  // the final container.
1047  bool keep = true;
1048  for (auto j : index_range(monomial_var_names))
1049  if (derived_var_name == monomial_var_names[j])
1050  {
1051  if (!found_first[j])
1052  found_first[j] = 1;
1053 
1054  else
1055  keep = false;
1056  }
1057 
1058  // We also don't keep variables that are not active on any subdomains.
1059  // Contrary to other uses of the var_active_subdomains container where
1060  // the empty set means "all" subdomains, here it really means "none".
1061  if (active_set.empty())
1062  keep = false;
1063 
1064  if (keep)
1065  {
1066  derived_var_names_edited.push_back(derived_var_name);
1067  derived_vars_active_subdomains_edited.push_back(active_set);
1068  }
1069  }
1070 
1071  // We built the filtered ranges, now swap them with the originals.
1072  derived_var_names.swap(derived_var_names_edited);
1073  derived_vars_active_subdomains.swap(derived_vars_active_subdomains_edited);
1074  }
1075 
1076 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1077  // Build complex variable names "r_foo", "i_foo", "a_foo" and the lists of
1078  // subdomains on which they are active.
1079  auto complex_var_names =
1080  exio_helper->get_complex_names(derived_var_names);
1081  auto complex_vars_active_subdomains =
1082  exio_helper->get_complex_vars_active_subdomains(derived_vars_active_subdomains);
1083  auto complex_subdomain_to_var_names =
1084  exio_helper->get_complex_subdomain_to_var_names(subdomain_to_var_names);
1085 
1086  // Make expanded version of vector "v" in which each entry in the
1087  // original expands to an ("r_", "i_", "a_") triple.
1088  std::vector<Real> complex_v;
1089  complex_v.reserve(3 * v.size());
1090  for (const auto & val : v)
1091  {
1092  complex_v.push_back(val.real());
1093  complex_v.push_back(val.imag());
1094  complex_v.push_back(std::abs(val));
1095  }
1096 
1097  // Finally, initialize storage for the variables and write them to file.
1098  exio_helper->initialize_element_variables
1099  (complex_var_names, complex_vars_active_subdomains);
1100  exio_helper->write_element_values_element_major
1101  (mesh, complex_v, _timestep,
1102  complex_vars_active_subdomains,
1103  complex_var_names,
1104  complex_subdomain_to_var_names);
1105 #else
1106 
1107  // Call function which writes the derived variable names to the
1108  // Exodus file.
1109  exio_helper->initialize_element_variables(derived_var_names, derived_vars_active_subdomains);
1110 
1111  // ES::build_discontinuous_solution_vector() creates a vector with
1112  // an element-major ordering, so call Helper::write_element_values()
1113  // passing false for the last argument.
1114  exio_helper->write_element_values_element_major
1115  (mesh, v, _timestep,
1116  derived_vars_active_subdomains,
1117  derived_var_names,
1118  subdomain_to_var_names);
1119 #endif
1120 }
1121 
1122 
1123 
1124 void ExodusII_IO::write_nodal_data (const std::string & fname,
1125  const std::vector<Number> & soln,
1126  const std::vector<std::string> & names)
1127 {
1128  LOG_SCOPE("write_nodal_data()", "ExodusII_IO");
1129 
1131 
1132  int num_vars = cast_int<int>(names.size());
1133  dof_id_type num_nodes = mesh.n_nodes();
1134 
1135  // The names of the variables to be output
1136  std::vector<std::string> output_names;
1137 
1138  if (_allow_empty_variables || !_output_variables.empty())
1139  output_names = _output_variables;
1140  else
1141  output_names = names;
1142 
1143 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1144 
1145  std::vector<std::string> complex_names = exio_helper->get_complex_names(names);
1146 
1147  // Call helper function for opening/initializing data, giving it the
1148  // complex variable names
1149  this->write_nodal_data_common(fname, complex_names, /*continuous=*/true);
1150 #else
1151  // Call helper function for opening/initializing data
1152  this->write_nodal_data_common(fname, output_names, /*continuous=*/true);
1153 #endif
1154 
1155  if (mesh.processor_id())
1156  return;
1157 
1158  // This will count the number of variables actually output
1159  for (int c=0; c<num_vars; c++)
1160  {
1161  std::stringstream name_to_find;
1162 
1163  std::vector<std::string>::iterator pos =
1164  std::find(output_names.begin(), output_names.end(), names[c]);
1165  if (pos == output_names.end())
1166  continue;
1167 
1168  unsigned int variable_name_position =
1169  cast_int<unsigned int>(pos - output_names.begin());
1170 
1171  // Set up temporary vectors to be passed to Exodus to write the
1172  // nodal values for a single variable at a time.
1173 #ifdef LIBMESH_USE_REAL_NUMBERS
1174  std::vector<Number> cur_soln;
1175 
1176  // num_nodes is either exactly how much space we will need for
1177  // each vector, or a safe upper bound for the amount of memory
1178  // we will require when there are gaps in the numbering.
1179  cur_soln.reserve(num_nodes);
1180 #else
1181  std::vector<Real> real_parts;
1182  std::vector<Real> imag_parts;
1183  std::vector<Real> magnitudes;
1184  real_parts.reserve(num_nodes);
1185  imag_parts.reserve(num_nodes);
1186  magnitudes.reserve(num_nodes);
1187 #endif
1188 
1189  // There could be gaps in "soln", but it will always be in the
1190  // order of [num_vars * node_id + var_id]. We now copy the
1191  // proper solution values contiguously into "cur_soln",
1192  // removing the gaps.
1193  for (const auto & node : mesh.node_ptr_range())
1194  {
1195  dof_id_type idx = node->id()*num_vars + c;
1196 #ifdef LIBMESH_USE_REAL_NUMBERS
1197  cur_soln.push_back(soln[idx]);
1198 #else
1199  real_parts.push_back(soln[idx].real());
1200  imag_parts.push_back(soln[idx].imag());
1201  magnitudes.push_back(std::abs(soln[idx]));
1202 #endif
1203  }
1204 
1205  // Finally, actually call the Exodus API to write to file.
1206 #ifdef LIBMESH_USE_REAL_NUMBERS
1207  exio_helper->write_nodal_values(variable_name_position+1, cur_soln, _timestep);
1208 #else
1209  exio_helper->write_nodal_values(3*variable_name_position+1, real_parts, _timestep);
1210  exio_helper->write_nodal_values(3*variable_name_position+2, imag_parts, _timestep);
1211  exio_helper->write_nodal_values(3*variable_name_position+3, magnitudes, _timestep);
1212 #endif
1213 
1214  }
1215 }
1216 
1217 
1218 
1219 
1220 void ExodusII_IO::write_information_records (const std::vector<std::string> & records)
1221 {
1223  return;
1224 
1225  if (!exio_helper->opened_for_writing)
1226  libmesh_error_msg("ERROR, ExodusII file must be initialized before outputting information records.");
1227 
1228  exio_helper->write_information_records(records);
1229 }
1230 
1231 
1232 
1233 void ExodusII_IO::write_global_data (const std::vector<Number> & soln,
1234  const std::vector<std::string> & names)
1235 {
1237  return;
1238 
1239  if (!exio_helper->opened_for_writing)
1240  libmesh_error_msg("ERROR, ExodusII file must be initialized before outputting global variables.");
1241 
1242 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1243 
1244  std::vector<std::string> complex_names = exio_helper->get_complex_names(names);
1245 
1246  exio_helper->initialize_global_variables(complex_names);
1247 
1248  unsigned int num_values = soln.size();
1249  unsigned int num_vars = names.size();
1250  unsigned int num_elems = num_values / num_vars;
1251 
1252  // This will contain the real and imaginary parts and the magnitude
1253  // of the values in soln
1254  std::vector<Real> complex_soln(3*num_values);
1255 
1256  for (unsigned i=0; i<num_vars; ++i)
1257  {
1258 
1259  for (unsigned int j=0; j<num_elems; ++j)
1260  {
1261  Number value = soln[i*num_vars + j];
1262  complex_soln[3*i*num_elems + j] = value.real();
1263  }
1264  for (unsigned int j=0; j<num_elems; ++j)
1265  {
1266  Number value = soln[i*num_vars + j];
1267  complex_soln[3*i*num_elems + num_elems +j] = value.imag();
1268  }
1269  for (unsigned int j=0; j<num_elems; ++j)
1270  {
1271  Number value = soln[i*num_vars + j];
1272  complex_soln[3*i*num_elems + 2*num_elems + j] = std::abs(value);
1273  }
1274  }
1275 
1276  exio_helper->write_global_values(complex_soln, _timestep);
1277 
1278 #else
1279  exio_helper->initialize_global_variables(names);
1280  exio_helper->write_global_values(soln, _timestep);
1281 #endif
1282 }
1283 
1284 
1285 
1286 void ExodusII_IO::write_timestep (const std::string & fname,
1287  const EquationSystems & es,
1288  const int timestep,
1289  const Real time,
1290  const std::set<std::string> * system_names)
1291 {
1292  _timestep = timestep;
1293  write_equation_systems(fname,es,system_names);
1294 
1296  return;
1297 
1298  exio_helper->write_timestep(timestep, time);
1299 }
1300 
1301 
1302 
1303 void
1305 write_sideset_data(int timestep,
1306  const std::vector<std::string> & var_names,
1307  const std::vector<std::set<boundary_id_type>> & side_ids,
1308  const std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
1309 {
1310  if (!exio_helper->opened_for_writing)
1311  libmesh_error_msg("ERROR, ExodusII file must be opened for writing "
1312  "before calling ExodusII_IO::write_sideset_data()!");
1313 
1315  exio_helper->write_sideset_data(mesh, timestep, var_names, side_ids, bc_vals);
1316 }
1317 
1318 
1319 
1320 void
1322 read_sideset_data(int timestep,
1323  std::vector<std::string> & var_names,
1324  std::vector<std::set<boundary_id_type>> & side_ids,
1325  std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
1326 {
1327  if (!exio_helper->opened_for_reading)
1328  libmesh_error_msg("ERROR, ExodusII file must be opened for reading "
1329  "before calling ExodusII_IO::read_sideset_data()!");
1330 
1332  exio_helper->read_sideset_data(mesh, timestep, var_names, side_ids, bc_vals);
1333 }
1334 
1335 
1336 
1337 
1338 void ExodusII_IO::write (const std::string & fname)
1339 {
1341 
1342  // We may need to gather a DistributedMesh to output it, making that
1343  // const qualifier in our constructor a dirty lie
1344  // The "true" specifies that we only need the mesh serialized to processor 0
1346 
1347  libmesh_assert( !exio_helper->opened_for_writing );
1348 
1349  // If the user has set the append flag here, it doesn't really make
1350  // sense: the intent of this function is to write a Mesh with no
1351  // data, while "appending" is really intended to add data to an
1352  // existing file. If we're verbose, print a message to this effect.
1353  if (_append && _verbose)
1354  libmesh_warning("Warning: Appending in ExodusII_IO::write() does not make sense.\n"
1355  "Creating a new file instead!");
1356 
1357  exio_helper->create(fname);
1358  exio_helper->initialize(fname,mesh);
1359  exio_helper->write_nodal_coordinates(mesh);
1360  exio_helper->write_elements(mesh);
1361  exio_helper->write_sidesets(mesh);
1362  exio_helper->write_nodesets(mesh);
1363 
1364  if ((mesh.get_boundary_info().n_edge_conds() > 0) && _verbose)
1365  libmesh_warning("Warning: Mesh contains edge boundary IDs, but these "
1366  "are not supported by the ExodusII format.");
1367 }
1368 
1369 
1370 
1371 void ExodusII_IO::write_nodal_data_discontinuous (const std::string & fname,
1372  const std::vector<Number> & soln,
1373  const std::vector<std::string> & names)
1374 {
1375  LOG_SCOPE("write_nodal_data_discontinuous()", "ExodusII_IO");
1376 
1378 
1379  int num_vars = cast_int<int>(names.size());
1380  int num_nodes = 0;
1381  for (const auto & elem : mesh.active_element_ptr_range())
1382  num_nodes += elem->n_nodes();
1383 
1384 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1385 
1386  std::vector<std::string> complex_names = exio_helper->get_complex_names(names);
1387 
1388  // Call helper function for opening/initializing data, giving it the
1389  // complex variable names
1390  this->write_nodal_data_common(fname, complex_names, /*continuous=*/false);
1391 #else
1392  // Call helper function for opening/initializing data
1393  this->write_nodal_data_common(fname, names, /*continuous=*/false);
1394 #endif
1395 
1396  if (mesh.processor_id())
1397  return;
1398 
1399  for (int c=0; c<num_vars; c++)
1400  {
1401 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1402  std::vector<Real> real_parts(num_nodes);
1403  std::vector<Real> imag_parts(num_nodes);
1404  std::vector<Real> magnitudes(num_nodes);
1405 
1406  for (int i=0; i<num_nodes; ++i)
1407  {
1408  real_parts[i] = soln[i*num_vars + c].real();
1409  imag_parts[i] = soln[i*num_vars + c].imag();
1410  magnitudes[i] = std::abs(soln[i*num_vars + c]);
1411  }
1412  exio_helper->write_nodal_values(3*c+1,real_parts,_timestep);
1413  exio_helper->write_nodal_values(3*c+2,imag_parts,_timestep);
1414  exio_helper->write_nodal_values(3*c+3,magnitudes,_timestep);
1415 #else
1416  // Copy out this variable's solution
1417  std::vector<Number> cur_soln(num_nodes);
1418 
1419  for (int i=0; i<num_nodes; i++)
1420  cur_soln[i] = soln[i*num_vars + c];
1421 
1422  exio_helper->write_nodal_values(c+1,cur_soln,_timestep);
1423 #endif
1424  }
1425 }
1426 
1427 
1428 
1430  const std::vector<std::string> & names,
1431  bool continuous)
1432 {
1434 
1435  // This function can be called multiple times, we only want to open
1436  // the ExodusII file the first time it's called.
1437  if (!exio_helper->opened_for_writing)
1438  {
1439  // If we're appending, open() the file with read_only=false,
1440  // otherwise create() it and write the contents of the mesh to
1441  // it.
1442  if (_append)
1443  {
1444  exio_helper->open(fname.c_str(), /*read_only=*/false);
1445  // If we're appending, it's not valid to call exio_helper->initialize()
1446  // or exio_helper->initialize_nodal_variables(), but we do need to set up
1447  // certain aspects of the Helper object itself, such as the number of nodes
1448  // and elements. We do that by reading the header...
1449  exio_helper->read_header();
1450 
1451  // ...and reading the block info
1452  exio_helper->read_block_info();
1453  }
1454  else
1455  {
1456  exio_helper->create(fname);
1457 
1458  exio_helper->initialize(fname, mesh, !continuous);
1459  exio_helper->write_nodal_coordinates(mesh, !continuous);
1460  exio_helper->write_elements(mesh, !continuous);
1461 
1462  exio_helper->write_sidesets(mesh);
1463  exio_helper->write_nodesets(mesh);
1464 
1465  exio_helper->initialize_nodal_variables(names);
1466  }
1467  }
1468  else
1469  {
1470  // We are already open for writing, so check that the filename
1471  // passed to this function matches the filename currently in use
1472  // by the helper.
1473  if (fname != exio_helper->current_filename)
1474  libmesh_error_msg("Error! This ExodusII_IO object is already associated with file: " \
1475  << exio_helper->current_filename \
1476  << ", cannot use it with requested file: " \
1477  << fname);
1478  }
1479 }
1480 
1481 const std::vector<std::string> & ExodusII_IO::get_nodal_var_names()
1482 {
1483  exio_helper->read_var_names(ExodusII_IO_Helper::NODAL);
1484  return exio_helper->nodal_var_names;
1485 }
1486 
1487 const std::vector<std::string> & ExodusII_IO::get_elem_var_names()
1488 {
1489  exio_helper->read_var_names(ExodusII_IO_Helper::ELEMENTAL);
1490  return exio_helper->elem_var_names;
1491 }
1492 
1493 const std::vector<std::string> & ExodusII_IO::get_global_var_names()
1494 {
1495  exio_helper->read_var_names(ExodusII_IO_Helper::GLOBAL);
1496  return exio_helper->global_var_names;
1497 }
1498 
1500 {
1501  // Provide a warning when accessing the helper object
1502  // since it is a non-public API and is likely to see
1503  // future API changes
1504  libmesh_experimental();
1505 
1506  return *exio_helper;
1507 }
1508 
1509 
1510 // LIBMESH_HAVE_EXODUS_API is not defined, declare error() versions of functions...
1511 #else
1512 
1513 
1514 
1516 {
1517 }
1518 
1519 
1520 
1521 void ExodusII_IO::read (const std::string &)
1522 {
1523  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1524 }
1525 
1526 
1527 
1528 void ExodusII_IO::verbose (bool)
1529 {
1530  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1531 }
1532 
1533 
1534 
1536 {
1537  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1538 }
1539 
1540 
1541 
1542 void ExodusII_IO::write_as_dimension(unsigned)
1543 {
1544  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1545 }
1546 
1547 
1548 
1550 {
1551  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1552 }
1553 
1554 
1555 
1556 void ExodusII_IO::append(bool)
1557 {
1558  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1559 }
1560 
1561 
1562 
1563 const std::vector<Real> & ExodusII_IO::get_time_steps()
1564 {
1565  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1566 }
1567 
1568 
1569 
1571 {
1572  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1573 }
1574 
1575 
1576 void ExodusII_IO::copy_nodal_solution(System &,
1577  std::string,
1578  std::string,
1579  unsigned int)
1580 {
1581  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1582 }
1583 
1584 
1585 
1587  std::string,
1588  std::string,
1589  unsigned int)
1590 {
1591  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1592 }
1593 
1594 
1595 
1596 void ExodusII_IO::copy_scalar_solution(System &,
1597  std::vector<std::string>,
1598  std::vector<std::string>,
1599  unsigned int)
1600 {
1601  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1602 }
1603 
1604 
1605 
1606 void ExodusII_IO::write_element_data (const EquationSystems &)
1607 {
1608  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1609 }
1610 
1611 
1612 
1613 void
1615 (const EquationSystems &,
1616  const std::set<std::string> *,
1617  const std::string & )
1618 {
1619  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1620 }
1621 
1622 
1623 
1624 void ExodusII_IO::write_nodal_data (const std::string &,
1625  const std::vector<Number> &,
1626  const std::vector<std::string> &)
1627 {
1628  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1629 }
1630 
1631 
1632 
1633 void ExodusII_IO::write_information_records (const std::vector<std::string> &)
1634 {
1635  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1636 }
1637 
1638 
1639 
1640 void ExodusII_IO::write_global_data (const std::vector<Number> &,
1641  const std::vector<std::string> &)
1642 {
1643  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1644 }
1645 
1646 
1647 
1648 void ExodusII_IO::write_timestep (const std::string &,
1649  const EquationSystems &,
1650  const int,
1651  const Real,
1652  const std::set<std::string> *)
1653 {
1654  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1655 }
1656 
1657 
1658 
1659 void
1661 write_sideset_data (int,
1662  const std::vector<std::string> &,
1663  const std::vector<std::set<boundary_id_type>> &,
1664  const std::vector<std::map<BoundaryInfo::BCTuple, Real>> &)
1665 {
1666  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1667 }
1668 
1669 
1670 
1671 void
1673 read_sideset_data (int,
1674  std::vector<std::string> &,
1675  std::vector<std::set<boundary_id_type>> &,
1676  std::vector<std::map<BoundaryInfo::BCTuple, Real>> &)
1677 {
1678  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1679 }
1680 
1681 
1682 
1683 void ExodusII_IO::write (const std::string &)
1684 {
1685  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1686 }
1687 
1688 
1689 
1690 void ExodusII_IO::write_nodal_data_discontinuous (const std::string &,
1691  const std::vector<Number> &,
1692  const std::vector<std::string> &)
1693 {
1694  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1695 }
1696 
1697 
1698 
1699 void ExodusII_IO::write_nodal_data_common(std::string,
1700  const std::vector<std::string> &,
1701  bool)
1702 {
1703  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1704 }
1705 
1706 
1707 const std::vector<std::string> & ExodusII_IO::get_elem_var_names()
1708 {
1709  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1710 }
1711 
1712 const std::vector<std::string> & ExodusII_IO::get_nodal_var_names()
1713 {
1714  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1715 }
1716 
1717 const std::vector<std::string> & ExodusII_IO::get_global_var_names()
1718 {
1719  libmesh_error_msg("ERROR, ExodusII API is not defined.");
1720 }
1721 
1722 #endif // LIBMESH_HAVE_EXODUS_API
1723 } // namespace libMesh
libMesh::ExodusII_IO::write_nodal_data_common
void write_nodal_data_common(std::string fname, const std::vector< std::string > &names, bool continuous=true)
This function factors out a bunch of code which is common to the write_nodal_data() and write_nodal_d...
Definition: exodusII_io.C:1429
libMesh::System
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:100
libMesh::Number
Real Number
Definition: libmesh_common.h:195
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::EquationSystems::build_elemental_solution_vector
void build_elemental_solution_vector(std::vector< Number > &soln, std::vector< std::string > &names) const
Retrieve the solution data for CONSTANT MONOMIALs.
Definition: equation_systems.C:883
libMesh::ExodusII_IO::copy_elemental_solution
void copy_elemental_solution(System &system, std::string system_var_name, std::string exodus_var_name, unsigned int timestep=1)
If we read in a elemental solution while reading in a mesh, we can attempt to copy that elemental sol...
Definition: exodusII_io.C:529
libMesh::ExodusII_IO::read_global_variable
void read_global_variable(std::vector< std::string > global_var_names, unsigned int timestep, std::vector< Real > &global_values)
Given a vector of global variables and a time step, returns the values of the global variable at the ...
Definition: exodusII_io.C:630
libMesh::MeshBase::reserve_nodes
virtual void reserve_nodes(const dof_id_type nn)=0
Reserves space for a known number of nodes.
libMesh::ExodusII_IO::write_as_dimension
void write_as_dimension(unsigned dim)
Directly control the num_dim which is written to the Exodus file.
Definition: exodusII_io.C:451
libMesh::ExodusII_IO::verbose
void verbose(bool set_verbosity)
Set the flag indicating if we should be verbose.
Definition: exodusII_io.C:434
libMesh::MeshBase::get_boundary_info
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:132
libMesh::BoundaryInfo::add_node
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
Definition: boundary_info.C:636
libMesh::ExodusII_IO_Helper
This is the ExodusII_IO_Helper class.
Definition: exodusII_io_helper.h:80
libMesh::MeshBase::active_element_ptr_range
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
libMesh::DofObject::set_id
dof_id_type & set_id()
Definition: dof_object.h:776
libMesh::MeshBase::elem_ref
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:521
libMesh::ExodusII_IO::write_sideset_data
void write_sideset_data(int timestep, const std::vector< std::string > &var_names, const std::vector< std::set< boundary_id_type >> &side_ids, const std::vector< std::map< BoundaryInfo::BCTuple, Real >> &bc_vals)
The Exodus format can also store values on sidesets.
Definition: exodusII_io.C:1305
libMesh::index_range
IntRange< std::size_t > index_range(const std::vector< T > &vec)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:106
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::Elem::dim
virtual unsigned short dim() const =0
libMesh::ExodusII_IO::write_element_data
void write_element_data(const EquationSystems &es)
Write out element solution.
Definition: exodusII_io.C:662
end
IterBase * end
Also have a polymorphic pointer to the end object, this prevents iterating past the end.
Definition: variant_filter_iterator.h:343
libMesh::BoundaryInfo::sideset_name
std::string & sideset_name(boundary_id_type id)
Definition: boundary_info.C:2341
libMesh::ExodusII_IO::copy_scalar_solution
void copy_scalar_solution(System &system, std::vector< std::string > system_var_names, std::vector< std::string > exodus_var_names, unsigned int timestep=1)
Copy global variables into scalar variables of a System object.
Definition: exodusII_io.C:571
libMesh::ParallelObject::comm
const Parallel::Communicator & comm() const
Definition: parallel_object.h:94
libMesh::ExodusII_IO::_timestep
int _timestep
Stores the current value of the timestep when calling ExodusII_IO::write_timestep().
Definition: exodusII_io.h:400
libMesh::System::number
unsigned int number() const
Definition: system.h:2075
libMesh::ExodusII_IO::get_num_time_steps
int get_num_time_steps()
Definition: exodusII_io.C:484
libMesh::BoundaryInfo::n_edge_conds
std::size_t n_edge_conds() const
Definition: boundary_info.C:1636
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::MeshBase::node_ptr
virtual const Node * node_ptr(const dof_id_type i) const =0
libMesh::MeshBase::mesh_dimension
unsigned int mesh_dimension() const
Definition: mesh_base.C:135
libMesh::ExodusII_IO::get_exio_helper
ExodusII_IO_Helper & get_exio_helper()
Return a reference to the ExodusII_IO_Helper object.
Definition: exodusII_io.C:1499
libMesh::ExodusII_IO::write_timestep
void write_timestep(const std::string &fname, const EquationSystems &es, const int timestep, const Real time, const std::set< std::string > *system_names=nullptr)
Writes out the solution at a specific timestep.
Definition: exodusII_io.C:1286
libMesh::boundary_id_type
int8_t boundary_id_type
Definition: id_types.h:51
dim
unsigned int dim
Definition: adaptivity_ex3.C:113
libMesh::ExodusII_IO::write_discontinuous_exodusII
void write_discontinuous_exodusII(const std::string &name, const EquationSystems &es, const std::set< std::string > *system_names=nullptr)
Writes a exodusII file with discontinuous data.
Definition: exodusII_io.C:93
libMesh::ExodusII_IO::write_information_records
void write_information_records(const std::vector< std::string > &)
Write out information records.
Definition: exodusII_io.C:1220
libMesh::ExodusII_IO::write_element_data_from_discontinuous_nodal_data
void write_element_data_from_discontinuous_nodal_data(const EquationSystems &es, const std::set< std::string > *system_names=nullptr, const std::string &var_suffix="_elem_node_")
Similar to the function above, but instead of only handling (CONSTANT, MONOMIAL) data,...
Definition: exodusII_io.C:766
libMesh::ExodusII_IO::use_mesh_dimension_instead_of_spatial_dimension
void use_mesh_dimension_instead_of_spatial_dimension(bool val)
In the general case, meshes containing 2D elements can be manifolds living in 3D space,...
Definition: exodusII_io.C:444
libMesh::ExodusII_IO::write_global_data
void write_global_data(const std::vector< Number > &, const std::vector< std::string > &)
Write out global variables.
Definition: exodusII_io.C:1233
libMesh::BoundaryInfo::nodeset_name
std::string & nodeset_name(boundary_id_type id)
Definition: boundary_info.C:2357
libMesh::ExodusII_IO::write_nodal_data
virtual void write_nodal_data(const std::string &, const std::vector< Number > &, const std::vector< std::string > &) override
Write out a nodal solution.
Definition: exodusII_io.C:1124
libMesh::DofObject::dof_number
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
Definition: dof_object.h:956
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::ExodusII_IO::_verbose
bool _verbose
should we be verbose?
Definition: exodusII_io.h:405
libMesh::ExodusII_IO::set_coordinate_offset
void set_coordinate_offset(Point p)
Allows you to set a vector that is added to the coordinates of all of the nodes.
Definition: exodusII_io.C:458
libMesh::ExodusII_IO::copy_nodal_solution
void copy_nodal_solution(System &system, std::string var_name, unsigned int timestep=1)
Backward compatibility version of function that takes a single variable name.
Definition: exodusII_io.C:82
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
libMesh::ExodusII_IO::~ExodusII_IO
virtual ~ExodusII_IO()
Destructor.
Definition: exodusII_io.C:136
std::abs
MetaPhysicL::DualNumber< T, D > abs(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::ExodusII_IO::get_global_var_names
const std::vector< std::string > & get_global_var_names()
Return list of the global variable names.
Definition: exodusII_io.C:1493
libMesh::ExodusII_IO::read_sideset_data
void read_sideset_data(int timestep, std::vector< std::string > &var_names, std::vector< std::set< boundary_id_type >> &side_ids, std::vector< std::map< BoundaryInfo::BCTuple, Real >> &bc_vals)
Similar to write_sideset_data(), this function is used to read the data at a particular timestep.
Definition: exodusII_io.C:1322
libMesh::MeshSerializer
Temporarily serialize a DistributedMesh for output; a distributed mesh is allgathered by the MeshSeri...
Definition: mesh_serializer.h:42
libMesh::ParallelObject::n_processors
processor_id_type n_processors() const
Definition: parallel_object.h:100
libMesh::System::variable_scalar_number
unsigned int variable_scalar_number(const std::string &var, unsigned int component) const
Definition: system.h:2214
libMesh::MeshBase::node_ptr_range
virtual SimpleRange< node_iterator > node_ptr_range()=0
libMesh::EquationSystems::build_variable_names
void build_variable_names(std::vector< std::string > &var_names, const FEType *type=nullptr, const std::set< std::string > *system_names=nullptr) const
Fill the input vector var_names with the names of the variables for each system.
Definition: equation_systems.C:476
libMesh::DofObject::n_comp
unsigned int n_comp(const unsigned int s, const unsigned int var) const
Definition: dof_object.h:926
libMesh::ExodusII_IO::_output_variables
std::vector< std::string > _output_variables
The names of the variables to be output.
Definition: exodusII_io.h:418
libMesh::ParallelObject::processor_id
processor_id_type processor_id() const
Definition: parallel_object.h:106
libMesh::ExodusII_IO::_append
bool _append
Default false.
Definition: exodusII_io.h:411
libMesh::ExodusII_IO_Helper::Conversion::invalid_id
static const int invalid_id
An invalid_id that can be returned to signal failure in case something goes wrong.
Definition: exodusII_io_helper.h:922
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::DofMap::SCALAR_dof_indices
void SCALAR_dof_indices(std::vector< dof_id_type > &di, const unsigned int vn, const bool old_dofs=false) const
Fills the vector di with the global degree of freedom indices corresponding to the SCALAR variable vn...
Definition: dof_map.C:2488
libMesh::ExodusII_IO::exio_helper
std::unique_ptr< ExodusII_IO_Helper > exio_helper
Only attempt to instantiate an ExodusII helper class if the Exodus API is defined.
Definition: exodusII_io.h:394
libMesh::Node
A Node is like a Point, but with more information.
Definition: node.h:52
libMesh::ExodusII_IO::_allow_empty_variables
bool _allow_empty_variables
If true, _output_variables is allowed to remain empty.
Definition: exodusII_io.h:425
libMesh::MeshTools::Generation::Private::idx
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)
A useful inline function which replaces the macros used previously.
Definition: mesh_generation.C:72
libMesh::CONSTANT
Definition: enum_order.h:41
libMesh::ExodusII_IO::get_time_steps
const std::vector< Real > & get_time_steps()
Definition: exodusII_io.C:473
libMesh::DofObject::unique_id
unique_id_type unique_id() const
Definition: dof_object.h:784
libMesh::Utility::enum_to_string
std::string enum_to_string(const T e)
libMesh::ExodusII_IO::get_nodal_var_names
const std::vector< std::string > & get_nodal_var_names()
Return list of the nodal variable names.
Definition: exodusII_io.C:1481
libMesh::ExodusII_IO::append
void append(bool val)
If true, this flag will cause the ExodusII_IO object to attempt to open an existing file for writing,...
Definition: exodusII_io.C:466
libMesh::ExodusII_IO_Helper::NODAL
Definition: exodusII_io_helper.h:692
libMesh::ExodusII_IO::read_elemental_variable
void read_elemental_variable(std::string elemental_var_name, unsigned int timestep, std::map< unsigned int, Real > &unique_id_to_value_map)
Given an elemental variable and a time step, returns a mapping from the elements (top parent) unique ...
Definition: exodusII_io.C:615
libMesh::MONOMIAL
Definition: enum_fe_family.h:39
libMesh::EquationSystems
This is the EquationSystems class.
Definition: equation_systems.h:74
libMesh::Elem::set_node
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2059
libMesh::MeshOutput< MeshBase >::write_equation_systems
virtual void write_equation_systems(const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
This method implements writing a mesh with data to a specified file where the data is taken from the ...
Definition: mesh_output.C:31
libMesh::System::variable_type
const FEType & variable_type(const unsigned int i) const
Definition: system.h:2233
libMesh::MeshBase::n_nodes
virtual dof_id_type n_nodes() const =0
libMesh::ExodusII_IO_Helper::ELEMENTAL
Definition: exodusII_io_helper.h:692
distance
Real distance(const Point &p)
Definition: subdomains_ex3.C:50
libMesh::MeshOutput
This class defines an abstract interface for Mesh output.
Definition: mesh_output.h:53
libMesh::System::solution
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1539
libMesh::ExodusII_IO::write_timestep_discontinuous
void write_timestep_discontinuous(const std::string &fname, const EquationSystems &es, const int timestep, const Real time, const std::set< std::string > *system_names=nullptr)
Writes a discontinuous solution at a specific timestep.
Definition: exodusII_io.C:107
libMesh::FEType
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:178
libMesh::MeshOutput::mesh
const MT & mesh() const
Definition: mesh_output.h:247
value
static const bool value
Definition: xdr_io.C:56
libMesh::MeshBase::add_elem
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
libMesh::DofMap
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:176
libMesh::Elem::subdomain_id
subdomain_id_type subdomain_id() const
Definition: elem.h:2069
libMesh::DofObject::id
dof_id_type id() const
Definition: dof_object.h:767
libMesh::EquationSystems::build_discontinuous_solution_vector
void build_discontinuous_solution_vector(std::vector< Number > &soln, const std::set< std::string > *system_names=nullptr, const std::vector< std::string > *var_names=nullptr, bool vertices_only=false) const
Fill the input vector soln with solution values.
Definition: equation_systems.C:1049
libMesh::MeshOutput< MeshBase >::write_discontinuous_equation_systems
virtual void write_discontinuous_equation_systems(const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
This method implements writing a mesh with discontinuous data to a specified file where the data is t...
Definition: mesh_output.C:87
libMesh::MeshBase::subdomain_name
std::string & subdomain_name(subdomain_id_type id)
Definition: mesh_base.C:717
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::System::variable_number
unsigned short int variable_number(const std::string &var) const
Definition: system.C:1232
libMesh::ExodusII_IO::get_elem_var_names
const std::vector< std::string > & get_elem_var_names()
Return list of the elemental variable names.
Definition: exodusII_io.C:1487
libMesh::ExodusII_IO::ExodusII_IO
ExodusII_IO(MeshBase &mesh, bool single_precision=false)
Constructor.
Definition: exodusII_io.C:49
libMesh::ExodusII_IO::write_nodal_data_discontinuous
void write_nodal_data_discontinuous(const std::string &, const std::vector< Number > &, const std::vector< std::string > &) override
Write out a discontinuous nodal solution.
Definition: exodusII_io.C:1371
libMesh::MeshInput< MeshBase >::mesh
MeshBase & mesh()
Definition: mesh_input.h:169
libMesh::ExodusII_IO::write
virtual void write(const std::string &fname) override
This method implements writing a mesh to a specified file.
Definition: exodusII_io.C:1338
libMesh::System::get_dof_map
const DofMap & get_dof_map() const
Definition: system.h:2099
libMesh::BoundaryInfo::add_shellface
void add_shellface(const dof_id_type elem, const unsigned short int shellface, const boundary_id_type id)
Add shell face shellface of element number elem with boundary id id to the boundary information data ...
Definition: boundary_info.C:794
libMesh::MeshBase::add_point
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
libMesh::ExodusII_IO_Helper::GLOBAL
Definition: exodusII_io_helper.h:692
libMesh::TestClass
Definition: id_types.h:33
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::ParallelObject
An object whose state is distributed along a set of processors.
Definition: parallel_object.h:55
libMesh::ExodusII_IO::read
virtual void read(const std::string &name) override
This method implements reading a mesh from a specified file.
Definition: exodusII_io.C:143
libMesh::MeshBase::clear
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:429
libMesh::MeshBase::set_mesh_dimension
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition: mesh_base.h:218
libMesh::Elem::build
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:246
libMesh::BoundaryInfo::add_side
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure.
Definition: boundary_info.C:886
libMesh::System::update
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:408
libMesh::Elem::type
virtual ElemType type() const =0
std::imag
boost::multiprecision::float128 imag(const boost::multiprecision::float128)
Definition: float128_shims.h:83
libMesh::MeshBase::reserve_elem
virtual void reserve_elem(const dof_id_type ne)=0
Reserves space for a known number of elements.
libMesh::Quality::name
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
libMesh::MeshInput
This class defines an abstract interface for Mesh input.
Definition: mesh_base.h:60
libMesh::EquationSystems::get_vars_active_subdomains
void get_vars_active_subdomains(const std::vector< std::string > &names, std::vector< std::set< subdomain_id_type >> &vars_active_subdomains) const
Retrieve vars_active_subdomains, which indicates the active subdomains for each variable in names.
Definition: equation_systems.C:841
libMesh::MeshInput< MeshBase >::elems_of_dimension
std::vector< bool > elems_of_dimension
A vector of bools describing what dimension elements have been encountered when reading a mesh.
Definition: mesh_input.h:97
libMesh::ExodusII_IO::set_output_variables
void set_output_variables(const std::vector< std::string > &output_variables, bool allow_empty=true)
Sets the list of variable names to be included in the output.
Definition: exodusII_io.C:72
libMesh::Elem::top_parent
const Elem * top_parent() const
Definition: elem.h:2460
std::real
boost::multiprecision::float128 real(const boost::multiprecision::float128 in)
Definition: float128_shims.h:77