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"
50 #ifdef LIBMESH_HAVE_EXODUS_API
61 #ifdef LIBMESH_HAVE_EXODUS_API
62 exio_helper(libmesh_make_unique<
ExodusII_IO_Helper>(*this, false, true, single_precision)),
67 _allow_empty_variables(false)
81 #ifdef LIBMESH_ENABLE_DEPRECATED
84 unsigned int timestep)
95 const std::set<std::string> * system_names)
97 std::vector<std::string> solution_names;
98 std::vector<Number> v;
106 #ifdef LIBMESH_HAVE_EXODUS_API
111 const std::set<std::string> * system_names)
127 const std::set<std::string> * )
134 #ifdef LIBMESH_HAVE_EXODUS_API
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 " \
215 int nelem_last_block = 0;
225 std::string subdomain_name =
exio_helper->get_block_name(i);
226 if (!subdomain_name.empty())
230 const std::string type_str (
exio_helper->get_elem_type());
231 const auto & conv =
exio_helper->get_conversion(type_str);
234 int jmax = nelem_last_block+
exio_helper->num_elem_this_blk;
235 for (
int j=nelem_last_block; j<jmax; j++)
239 elem->
subdomain_id() = static_cast<subdomain_id_type>(subdomain_id) ;
249 elem->
set_id(exodus_id-1);
259 if (elem->
id() != static_cast<unsigned>(exodus_id-1))
260 libmesh_error_msg(
"Error! Mesh assigned ID " \
262 <<
" which is different from the (zero-based) Exodus ID " \
267 for (
int k=0; k<
exio_helper->num_nodes_per_elem; k++)
270 int gi = (j-nelem_last_block)*
exio_helper->num_nodes_per_elem + conv.get_node_map(k);
288 nelem_last_block +=
exio_helper->num_elem_this_blk;
296 for (
unsigned char i=0; i!=4; ++i)
308 offset += (i > 0 ?
exio_helper->num_sides_per_set[i-1] : 0);
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)))
336 unsigned int raw_side_index =
exio_helper->side_list[e]-1;
337 std::size_t side_index_offset = conv.get_shellface_index_offset();
339 if (raw_side_index < side_index_offset)
342 int mapped_shellface = raw_side_index;
346 libmesh_error_msg(
"Invalid 1-based side id: " \
347 << mapped_shellface \
348 <<
" detected for " \
353 cast_int<unsigned short>(mapped_shellface),
354 cast_int<boundary_id_type>(
exio_helper->id_list[e]));
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);
363 libmesh_error_msg(
"Invalid 1-based side id: " \
365 <<
" detected for " \
370 cast_int<unsigned short>(mapped_side),
371 cast_int<boundary_id_type>(
exio_helper->id_list[e]));
388 for (
int nodeset=0; nodeset<
exio_helper->num_node_sets; nodeset++)
391 cast_int<boundary_id_type>(
exio_helper->nodeset_ids[nodeset]);
393 std::string nodeset_name =
exio_helper->get_node_set_name(nodeset);
394 if (!nodeset_name.empty())
398 unsigned int offset =
exio_helper->node_sets_node_index[nodeset];
400 for (
int i=0; i<
exio_helper->num_nodes_per_set[nodeset]; ++i)
402 int exodus_id =
exio_helper->node_sets_node_list[i + offset];
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);
415 int libmesh_node_id =
exio_helper->node_num_map[exodus_id - 1] - 1;
424 libmesh_error_msg(
"Cannot open dimension " \
426 <<
" mesh file when configured without " \
446 exio_helper->use_mesh_dimension_instead_of_spatial_dimension(val);
460 libmesh_warning(
"This method may be deprecated in the future");
476 libmesh_error_msg(
"ERROR, ExodusII file must be opened for reading before calling ExodusII_IO::get_time_steps()!");
487 libmesh_error_msg(
"ERROR, ExodusII file must be opened for reading or writing before calling ExodusII_IO::get_num_time_steps()!");
496 std::string system_var_name,
497 std::string exodus_var_name,
498 unsigned int timestep)
501 libmesh_error_msg(
"ERROR, ExodusII file must be opened for reading before copying a nodal solution!");
503 exio_helper->read_nodal_var_values(exodus_var_name, timestep);
508 n_nodal = cast_int<dof_id_type>(
exio_helper->nodal_var_values.size());
518 if ((dof_index >= system.
solution->first_local_index()) && (dof_index < system.solution->last_local_index()))
530 std::string system_var_name,
531 std::string exodus_var_name,
532 unsigned int timestep)
534 if (system.
comm().rank() == 0)
537 libmesh_error_msg(
"ERROR, ExodusII file must be opened for reading before copying an elemental solution!");
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);
549 libmesh_error_msg(
"Error! Trying to copy elemental solution into a variable that is not of CONSTANT MONOMIAL type.");
551 std::map<dof_id_type, Real>::iterator
552 it = elem_var_value_map.begin(),
553 end = elem_var_value_map.end();
555 for (; it!=
end; ++it)
562 system.
solution->set (dof_index, it->second);
572 std::vector<std::string> system_var_names,
573 std::vector<std::string> exodus_var_names,
574 unsigned int timestep)
577 libmesh_error_msg(
"ERROR, ExodusII file must be opened for reading before copying a scalar solution!");
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.");
582 std::vector<Real> values_from_exodus;
585 #ifdef LIBMESH_HAVE_MPI
588 const Parallel::MessageTag tag(1);
590 this->
comm().receive(0, values_from_exodus, tag);
604 std::vector<dof_id_type> SCALAR_dofs;
607 system.
solution->set (SCALAR_dofs[0], values_from_exodus[i]);
616 unsigned int timestep,
617 std::map<unsigned int, Real> & unique_id_to_value_map)
620 std::map<dof_id_type, Real> elem_var_value_map;
622 exio_helper->read_elemental_var_values(elemental_var_name, timestep, elem_var_value_map);
623 for (
auto & pr : elem_var_value_map)
631 unsigned int timestep,
632 std::vector<Real> & global_values)
634 std::size_t size = global_var_names.size();
636 libmesh_error_msg(
"ERROR, empty list of global variables to read from the Exodus file.");
639 std::vector<Real> values_from_exodus;
641 exio_helper->read_global_values(values_from_exodus, timestep);
642 std::vector<std::string> global_var_names_exodus =
exio_helper->global_var_names;
644 if (values_from_exodus.size() == 0)
647 global_values.clear();
648 for (std::size_t i = 0; i != size; ++i)
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()]);
656 libmesh_error_msg(
"ERROR, Global variable " << global_var_names[i] << \
657 " not found in Exodus file.");
666 libmesh_error_msg(
"ERROR, ExodusII file must be initialized before outputting element variables.");
680 std::vector<std::string> names;
686 std::vector<std::string> monomials;
694 for (
const auto & var : monomials)
696 names.push_back(var);
701 std::vector<Number> soln;
705 std::vector<std::set<subdomain_id_type>> vars_active_subdomains;
718 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
720 std::vector<std::string> complex_names =
exio_helper->get_complex_names(names);
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);
726 unsigned int num_values = soln.size();
727 unsigned int num_vars = names.size();
728 unsigned int num_elems = num_values / num_vars;
732 std::vector<Real> complex_soln(3*num_values);
734 for (
unsigned i=0; i<num_vars; ++i)
737 for (
unsigned int j=0; j<num_elems; ++j)
740 complex_soln[3*i*num_elems + j] =
value.real();
742 for (
unsigned int j=0; j<num_elems; ++j)
745 complex_soln[3*i*num_elems + num_elems +j] =
value.imag();
747 for (
unsigned int j=0; j<num_elems; ++j)
750 complex_soln[3*i*num_elems + 2*num_elems + j] =
std::abs(
value);
757 exio_helper->initialize_element_variables(names, vars_active_subdomains);
767 const std::set<std::string> * system_names,
768 const std::string & var_suffix)
774 libmesh_error_msg(
"ERROR, ExodusII file must be initialized before outputting element variables.");
788 std::vector<std::string> var_names;
794 std::vector<std::string> monomial_var_names;
802 if (!_output_variables.empty())
808 [
this](
const std::string &
name)
809 {
return !std::count(_output_variables.begin(),
810 _output_variables.end(),
815 monomial_var_names.erase
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(),
823 monomial_var_names.end());
829 std::vector<Number> v;
831 (v, system_names, &var_names,
true);
834 std::vector<std::set<subdomain_id_type>> vars_active_subdomains;
840 std::map<subdomain_id_type, unsigned int> subdomain_id_to_vertices_per_elem;
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.");
874 std::vector<std::string> derived_var_names;
879 std::map<std::string, std::pair<std::string, unsigned int>>
880 derived_name_to_orig_name_and_node_id;
882 for (
const auto & pr : subdomain_id_to_vertices_per_elem)
885 const unsigned int vertices_per_elem =
886 subdomain_id_to_vertices_per_elem[sbd_id];
888 std::ostringstream oss;
889 for (
unsigned int n=0; n<vertices_per_elem; ++n)
890 for (
const auto & orig_var_name : var_names)
894 oss << orig_var_name << var_suffix << n;
895 std::string derived_name = oss.str();
898 if (!std::count(derived_var_names.begin(), derived_var_names.end(), derived_name))
900 derived_var_names.push_back(derived_name);
902 derived_name_to_orig_name_and_node_id[derived_name] =
903 std::make_pair(orig_var_name, n);
911 std::vector<std::set<subdomain_id_type>>
912 derived_vars_active_subdomains(derived_var_names.size());
924 std::map<subdomain_id_type, std::vector<std::string>>
925 subdomain_to_var_names;
927 for (
auto derived_var_id :
index_range(derived_var_names))
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,
935 const std::string & orig_name = name_and_id.first;
936 const unsigned int node_id = name_and_id.second;
940 for (
const auto & pr : subdomain_id_to_vertices_per_elem)
945 unsigned int vertices_per_elem_this_sbd =
946 subdomain_id_to_vertices_per_elem[sbd_id];
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.");
960 if (node_id < vertices_per_elem_this_sbd)
966 subdomain_to_var_names[sbd_id].push_back(derived_name);
975 bool orig_var_active =
976 (vars_active_subdomains[var_id].empty() ||
977 vars_active_subdomains[var_id].count(sbd_id));
982 derived_vars_active_subdomains[derived_var_id].insert(sbd_id);
994 for (
auto & derived_var_name : derived_var_names)
997 const auto & name_and_id =
998 libmesh_map_find (derived_name_to_orig_name_and_node_id,
1002 const std::string & orig_name = name_and_id.first;
1005 if (std::count(monomial_var_names.begin(),
1006 monomial_var_names.end(),
1010 for (
auto & pr : subdomain_to_var_names)
1013 auto & name_vec = pr.second;
1016 std::find(name_vec.begin(),
1020 if (name_vec_it != name_vec.end())
1024 *name_vec_it = orig_name;
1029 derived_var_name = orig_name;
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());
1042 const auto & derived_var_name = derived_var_names[i];
1043 const auto & active_set = derived_vars_active_subdomains[i];
1049 if (derived_var_name == monomial_var_names[j])
1051 if (!found_first[j])
1061 if (active_set.empty())
1066 derived_var_names_edited.push_back(derived_var_name);
1067 derived_vars_active_subdomains_edited.push_back(active_set);
1072 derived_var_names.swap(derived_var_names_edited);
1073 derived_vars_active_subdomains.swap(derived_vars_active_subdomains_edited);
1076 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
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);
1088 std::vector<Real> complex_v;
1089 complex_v.reserve(3 * v.size());
1090 for (
const auto & val : v)
1092 complex_v.push_back(val.real());
1093 complex_v.push_back(val.imag());
1094 complex_v.push_back(
std::abs(val));
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,
1104 complex_subdomain_to_var_names);
1109 exio_helper->initialize_element_variables(derived_var_names, derived_vars_active_subdomains);
1114 exio_helper->write_element_values_element_major
1115 (
mesh, v, _timestep,
1116 derived_vars_active_subdomains,
1118 subdomain_to_var_names);
1125 const std::vector<Number> & soln,
1126 const std::vector<std::string> & names)
1128 LOG_SCOPE(
"write_nodal_data()",
"ExodusII_IO");
1132 int num_vars = cast_int<int>(names.size());
1136 std::vector<std::string> output_names;
1141 output_names = names;
1143 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1145 std::vector<std::string> complex_names =
exio_helper->get_complex_names(names);
1159 for (
int c=0; c<num_vars; c++)
1161 std::stringstream name_to_find;
1163 std::vector<std::string>::iterator pos =
1164 std::find(output_names.begin(), output_names.end(), names[c]);
1165 if (pos == output_names.end())
1168 unsigned int variable_name_position =
1169 cast_int<unsigned int>(pos - output_names.begin());
1173 #ifdef LIBMESH_USE_REAL_NUMBERS
1174 std::vector<Number> cur_soln;
1179 cur_soln.reserve(num_nodes);
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);
1196 #ifdef LIBMESH_USE_REAL_NUMBERS
1197 cur_soln.push_back(soln[
idx]);
1199 real_parts.push_back(soln[
idx].
real());
1200 imag_parts.push_back(soln[
idx].
imag());
1206 #ifdef LIBMESH_USE_REAL_NUMBERS
1226 libmesh_error_msg(
"ERROR, ExodusII file must be initialized before outputting information records.");
1234 const std::vector<std::string> & names)
1240 libmesh_error_msg(
"ERROR, ExodusII file must be initialized before outputting global variables.");
1242 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1244 std::vector<std::string> complex_names =
exio_helper->get_complex_names(names);
1246 exio_helper->initialize_global_variables(complex_names);
1248 unsigned int num_values = soln.size();
1249 unsigned int num_vars = names.size();
1250 unsigned int num_elems = num_values / num_vars;
1254 std::vector<Real> complex_soln(3*num_values);
1256 for (
unsigned i=0; i<num_vars; ++i)
1259 for (
unsigned int j=0; j<num_elems; ++j)
1262 complex_soln[3*i*num_elems + j] =
value.real();
1264 for (
unsigned int j=0; j<num_elems; ++j)
1267 complex_soln[3*i*num_elems + num_elems +j] =
value.imag();
1269 for (
unsigned int j=0; j<num_elems; ++j)
1272 complex_soln[3*i*num_elems + 2*num_elems + j] =
std::abs(
value);
1290 const std::set<std::string> * system_names)
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)
1311 libmesh_error_msg(
"ERROR, ExodusII file must be opened for writing "
1312 "before calling ExodusII_IO::write_sideset_data()!");
1315 exio_helper->write_sideset_data(
mesh, timestep, var_names, side_ids, bc_vals);
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)
1328 libmesh_error_msg(
"ERROR, ExodusII file must be opened for reading "
1329 "before calling ExodusII_IO::read_sideset_data()!");
1332 exio_helper->read_sideset_data(
mesh, timestep, var_names, side_ids, bc_vals);
1354 libmesh_warning(
"Warning: Appending in ExodusII_IO::write() does not make sense.\n"
1355 "Creating a new file instead!");
1365 libmesh_warning(
"Warning: Mesh contains edge boundary IDs, but these "
1366 "are not supported by the ExodusII format.");
1372 const std::vector<Number> & soln,
1373 const std::vector<std::string> & names)
1375 LOG_SCOPE(
"write_nodal_data_discontinuous()",
"ExodusII_IO");
1379 int num_vars = cast_int<int>(names.size());
1382 num_nodes += elem->n_nodes();
1384 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1386 std::vector<std::string> complex_names =
exio_helper->get_complex_names(names);
1399 for (
int c=0; c<num_vars; c++)
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);
1406 for (
int i=0; i<num_nodes; ++i)
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]);
1417 std::vector<Number> cur_soln(num_nodes);
1419 for (
int i=0; i<num_nodes; i++)
1420 cur_soln[i] = soln[i*num_vars + c];
1430 const std::vector<std::string> & names,
1474 libmesh_error_msg(
"Error! This ExodusII_IO object is already associated with file: " \
1476 <<
", cannot use it with requested file: " \
1504 libmesh_experimental();
1523 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1530 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1537 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1544 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1551 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1558 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1565 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1572 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1581 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1591 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1597 std::vector<std::string>,
1598 std::vector<std::string>,
1601 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1608 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1615 (
const EquationSystems &,
1616 const std::set<std::string> *,
1617 const std::string & )
1619 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1625 const std::vector<Number> &,
1626 const std::vector<std::string> &)
1628 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1635 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1641 const std::vector<std::string> &)
1643 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1649 const EquationSystems &,
1652 const std::set<std::string> *)
1654 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1662 const std::vector<std::string> &,
1663 const std::vector<std::set<boundary_id_type>> &,
1664 const std::vector<std::map<BoundaryInfo::BCTuple, Real>> &)
1666 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1674 std::vector<std::string> &,
1675 std::vector<std::set<boundary_id_type>> &,
1676 std::vector<std::map<BoundaryInfo::BCTuple, Real>> &)
1678 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1685 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1691 const std::vector<Number> &,
1692 const std::vector<std::string> &)
1694 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1700 const std::vector<std::string> &,
1703 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1709 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1714 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1719 libmesh_error_msg(
"ERROR, ExodusII API is not defined.");
1722 #endif // LIBMESH_HAVE_EXODUS_API