25#include "libmesh/nemesis_io_helper.h"
27#include "libmesh/boundary_info.h"
28#include "libmesh/dof_map.h"
29#include "libmesh/elem.h"
30#include "libmesh/equation_systems.h"
31#include "libmesh/fe_interface.h"
32#include "libmesh/int_range.h"
33#include "libmesh/mesh_base.h"
34#include "libmesh/node.h"
35#include "libmesh/numeric_vector.h"
36#include "libmesh/parallel.h"
37#include "libmesh/utility.h"
39#if defined(LIBMESH_HAVE_NEMESIS_API) && defined(LIBMESH_HAVE_EXODUS_API)
41#include <libmesh/ignore_warnings.h>
62# include "ne_nemesisI.h"
66#include <libmesh/restore_warnings.h>
78 bool verbose_in,
bool single_precision) :
83 num_elem_blks_global(0),
84 num_node_sets_global(0),
85 num_side_sets_global(0),
89 num_internal_nodes(0),
91 num_external_nodes(0),
92 num_internal_elems(0),
96 write_complex_abs(true)
99 libmesh_experimental();
111 EX_EXCEPTIONLESS_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
129 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset parameters.");
130 message(
"Parameters retrieved successfully for nodeset: ",
id);
144 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset data.");
145 message(
"Data retrieved successfully for nodeset: ",
id);
154 Nemesis::ne_get_init_global(
ex_id,
186 Nemesis::ne_get_ss_param_global(
ex_id,
194 libMesh::out <<
"[" << this->
processor_id() <<
"] " <<
"Global Sideset IDs, Side Counts, and DF counts:" << std::endl;
219 Nemesis::ne_get_ns_param_global(
ex_id,
227 libMesh::out <<
"[" << this->
processor_id() <<
"] " <<
"Global Nodeset IDs, Node Counts, and DF counts:" << std::endl;
250 Nemesis::ne_get_eb_info_global(
ex_id,
274 Nemesis::ne_get_init_info(
ex_id,
293 Nemesis::ne_get_loadbal_param(
ex_id,
326 Nemesis::ne_get_elem_map(
ex_id,
358 Nemesis::ne_get_node_map(
ex_id,
396 Nemesis::ne_get_cmap_params(
ex_id,
446 Nemesis::ne_get_node_cmap(
ex_id,
451 EX_CHECK_ERR(
nemesis_err_flag,
"Error reading node cmap node and processor ids!");
488 Nemesis::ne_get_elem_cmap(
ex_id,
494 EX_CHECK_ERR(
nemesis_err_flag,
"Error reading elem cmap elem, side, and processor ids!");
525 unsigned num_proc_in_file_in,
526 const char * ftype_in)
529 Nemesis::ne_put_init_info(
ex_id,
532 const_cast<char *
>(ftype_in));
542 unsigned num_elem_blks_global_in,
543 unsigned num_node_sets_global_in,
544 unsigned num_side_sets_global_in)
547 Nemesis::ne_put_init_global(
ex_id,
550 num_elem_blks_global_in,
551 num_node_sets_global_in,
552 num_side_sets_global_in);
560 std::vector<int> & global_elem_blk_cnts_in)
563 Nemesis::ne_put_eb_info_global(
ex_id,
564 global_elem_blk_ids_in.data(),
565 global_elem_blk_cnts_in.data());
567 EX_CHECK_ERR(
nemesis_err_flag,
"Error writing global element block information!");
574 std::vector<int> & num_global_node_counts_in,
575 std::vector<int> & num_global_node_df_counts_in)
581 Nemesis::ne_put_ns_param_global(
ex_id,
582 global_nodeset_ids_in.data(),
583 num_global_node_counts_in.data(),
584 num_global_node_df_counts_in.data());
594 std::vector<int> & num_global_side_counts_in,
595 std::vector<int> & num_global_side_df_counts_in)
601 Nemesis::ne_put_ss_param_global(
ex_id,
602 global_sideset_ids_in.data(),
603 num_global_side_counts_in.data(),
604 num_global_side_df_counts_in.data());
614 unsigned num_border_nodes_in,
615 unsigned num_external_nodes_in,
616 unsigned num_internal_elems_in,
617 unsigned num_border_elems_in,
618 unsigned num_node_cmaps_in,
619 unsigned num_elem_cmaps_in)
622 Nemesis::ne_put_loadbal_param(
ex_id,
623 num_internal_nodes_in,
625 num_external_nodes_in,
626 num_internal_elems_in,
640 std::vector<int> & node_cmap_node_cnts_in,
641 std::vector<int> & elem_cmap_ids_in,
642 std::vector<int> & elem_cmap_elem_cnts_in)
645 Nemesis::ne_put_cmap_params(
ex_id,
646 node_cmap_ids_in.empty() ?
nullptr : node_cmap_ids_in.data(),
647 node_cmap_node_cnts_in.empty() ? nullptr : node_cmap_node_cnts_in.data(),
648 elem_cmap_ids_in.empty() ? nullptr : elem_cmap_ids_in.data(),
649 elem_cmap_elem_cnts_in.empty() ? nullptr : elem_cmap_elem_cnts_in.data(),
659 std::vector<std::vector<int>> & node_cmap_proc_ids_in)
669 for (
const auto & node_id : node_cmap_node_ids_in[i])
677 for (
const auto & proc_id : node_cmap_proc_ids_in[i])
685 int * node_ids_ptr = node_cmap_node_ids_in[i].empty() ?
686 nullptr : node_cmap_node_ids_in[i].data();
687 int * proc_ids_ptr = node_cmap_proc_ids_in[i].empty() ?
688 nullptr : node_cmap_proc_ids_in[i].data();
692 node_ids_ptr, proc_ids_ptr,
695 EX_CHECK_ERR(
nemesis_err_flag,
"Error writing node communication map to file!");
703 std::vector<int> & node_mapb_in,
704 std::vector<int> & node_mape_in)
707 Nemesis::ne_put_node_map(
ex_id,
708 node_mapi_in.empty() ?
nullptr : node_mapi_in.data(),
709 node_mapb_in.empty() ? nullptr : node_mapb_in.data(),
710 node_mape_in.empty() ? nullptr : node_mape_in.data(),
713 EX_CHECK_ERR(
nemesis_err_flag,
"Error writing Nemesis internal and border node maps to file!");
720 std::vector<std::vector<int>> & elem_cmap_side_ids_in,
721 std::vector<std::vector<int>> & elem_cmap_proc_ids_in)
726 Nemesis::ne_put_elem_cmap(
ex_id,
728 elem_cmap_elem_ids_in[i].data(),
729 elem_cmap_side_ids_in[i].data(),
730 elem_cmap_proc_ids_in[i].data(),
733 EX_CHECK_ERR(
nemesis_err_flag,
"Error writing elem communication map to file!");
741 std::vector<int> & elem_mapb_in)
744 Nemesis::ne_put_elem_map(
ex_id,
745 elem_mapi_in.empty() ?
nullptr : elem_mapi_in.data(),
746 elem_mapb_in.empty() ? nullptr : elem_mapb_in.data(),
749 EX_CHECK_ERR(
nemesis_err_flag,
"Error writing Nemesis internal and border element maps to file!");
803 this->num_elem_blks_global,
804 this->num_node_sets_global,
805 this->num_side_sets_global
920 const std::string & title_in)
922 this->
num_elem =
static_cast<unsigned int>(std::distance (pmesh.active_local_elements_begin(),
923 pmesh.active_local_elements_end()));
943 this->num_side_sets);
945 EX_CHECK_ERR(
ex_err,
"Error initializing new Nemesis file.");
994 for (; it != end; ++it)
997 libmesh_assert_equal_to (
static_cast<unsigned>(this->
elem_cmap_ids[cnt]), it->first);
1000 std::set<std::pair<unsigned,unsigned>> & elem_set = it->second;
1007 std::set<std::pair<unsigned,unsigned>>::iterator elem_set_iter = elem_set.begin();
1010 for (std::size_t j=0, eceis=this->
elem_cmap_elem_ids[cnt].size(); j<eceis; ++j, ++elem_set_iter)
1063 libmesh_assert_less_equal
1065 std::size_t(this->num_node_cmaps));
1076 for (; it != end; ++it)
1079 libmesh_assert_equal_to (
static_cast<unsigned>(this->
node_cmap_ids[cnt]), it->first);
1082 std::set<unsigned> &
node_set = it->second;
1088 std::set<unsigned>::iterator node_set_iter =
node_set.begin();
1091 for (std::size_t j=0, nceis=this->
node_cmap_node_ids[cnt].size(); j<nceis; ++j, ++node_set_iter)
1119 for (
const auto & proc_id : id_vec)
1145 for (; it != end; ++it)
1180 for (; it != end; ++it)
1212 std::set<unsigned> all_elem_ids;
1217 std::set<unsigned> neighboring_processor_ids;
1219 for (
const auto & elem : pmesh.active_local_element_ptr_range())
1224 all_elem_ids.insert(elem->id());
1227 bool is_border_elem =
false;
1243 for (
auto node : elem->node_index_range())
1247 for (
auto n : elem->side_index_range())
1249 if (elem->neighbor_ptr(n) !=
nullptr)
1251 unsigned neighbor_proc_id = elem->neighbor_ptr(n)->processor_id();
1257 is_border_elem =
true;
1258 neighboring_processor_ids.insert(neighbor_proc_id);
1261 unsigned nemesis_side_id = conv.get_inverse_side_map(n);
1266 <<
" mapped to (1-based) Exodus side "
1286 std::set_difference(all_elem_ids.begin(), all_elem_ids.end(),
1287 this->border_elem_ids.begin(), this->border_elem_ids.end(),
1288 std::inserter(this->internal_elem_ids, this->internal_elem_ids.end()));
1292 this->border_node_ids.begin(), this->border_node_ids.end(),
1293 std::inserter(this->internal_node_ids, this->internal_node_ids.end()));
1298 for (
const auto &
id : neighboring_processor_ids)
1305 cast_int<int>(neighboring_processor_ids.size());
1309 <<
"Number of neighboring processor IDs="
1320 << proc_id <<
" communicates "
1321 << set.size() <<
" elements." << std::endl;
1348 std::set<boundary_id_type> global_side_boundary_ids
1357 cast_int<int>(global_side_boundary_ids.size());
1362 global_side_boundary_ids.begin(),
1363 global_side_boundary_ids.end());
1375 typedef std::tuple<dof_id_type, unsigned short int, boundary_id_type> Tuple;
1379 std::vector<Tuple>::iterator
1380 it = bc_triples.begin(),
1381 new_end = bc_triples.end();
1383 while (it != new_end)
1391 std::swap (*it, *new_end);
1398 bc_triples.erase(new_end, bc_triples.end());
1408 cast_int<int>(std::count_if(bc_triples.begin(),
1410 [
id](
const Tuple & t)->bool { return std::get<2>(t) == id; }));
1440 std::set<boundary_id_type> local_node_boundary_ids;
1443 std::set<boundary_id_type> global_node_boundary_ids
1448 local_node_boundary_ids = global_node_boundary_ids;
1455 cast_int<int>(global_node_boundary_ids.size());
1460 global_node_boundary_ids.begin(),
1461 global_node_boundary_ids.end());
1471 for (
const auto &
id : local_node_boundary_ids)
1479 typedef std::tuple<dof_id_type, boundary_id_type> Tuple;
1485 << bc_tuples.size() << std::endl;
1487 for (
const auto & t : bc_tuples)
1488 libMesh::out <<
"(" << std::get<0>(t) <<
", " << std::get<1>(t) <<
") ";
1503 std::vector<Tuple>::iterator
1504 it = bc_tuples.begin(),
1505 new_end = bc_tuples.end();
1507 while (it != new_end)
1515 std::swap(*it, *new_end);
1522 bc_tuples.erase(new_end, bc_tuples.end());
1529 cast_int<int>(std::count_if(bc_tuples.begin(),
1531 [
id](
const Tuple & t)->bool { return std::get<1>(t) == id; }));
1552 std::set<subdomain_id_type> global_subdomain_ids;
1555 std::map<subdomain_id_type, unsigned> global_subdomain_counts;
1557 for (
const auto & elem : pmesh.active_local_element_ptr_range())
1568 global_subdomain_ids.insert(cur_subdomain);
1571 global_subdomain_counts[cur_subdomain]++;
1579 std::vector<subdomain_id_type> global_subdomain_ids_vector(global_subdomain_ids.begin(),
1580 global_subdomain_ids.end());
1586 global_subdomain_ids.insert(global_subdomain_ids_vector.begin(),
1587 global_subdomain_ids_vector.end());
1592 cast_int<int>(global_subdomain_ids.size());
1598 for (
const auto & [subdomain_id, cnt] : global_subdomain_counts)
1601 <<
static_cast<unsigned>(subdomain_id)
1602 <<
", Count: " << cnt <<
", ";
1614 for (
const auto &
id : global_subdomain_ids)
1631 global_subdomain_ids.begin(),
1632 global_subdomain_ids.end());
1657 pmesh.active_local_elements_end());
1675 <<
"local_subdomain_counts [" <<
static_cast<unsigned>(sbd_id) <<
"]= "
1685 for (
const auto & elem : pmesh.active_local_element_ptr_range())
1688 for (
auto n : elem->node_index_range())
1739 for (
auto & [block_id, elem_ids_this_subdomain] :
subdomain_map)
1744 libmesh_error_msg_if(elem_ids_this_subdomain.size() == 0,
1745 "Error, no element IDs found in subdomain " << block_id);
1760 current_block_connectivity.clear();
1761 current_block_connectivity.resize(elem_ids_this_subdomain.size() * this->num_nodes_per_elem);
1763 for (
auto i :
index_range(elem_ids_this_subdomain))
1765 auto elem_id = elem_ids_this_subdomain[i];
1793 libmesh_assert_equal_to (elem.
n_nodes(),
Elem::build(conv.libmesh_elem_type(),
nullptr)->n_nodes());
1798 const unsigned int elem_node_index = conv.get_inverse_node_map(j);
1800 current_block_connectivity[connect_index] =
1802 elem.
node_id(elem_node_index));
1821 std::map<unsigned, std::set<unsigned>> proc_nodes_touched;
1829 for (
const auto & elem : pmesh.active_element_ptr_range())
1833 std::set<unsigned> & set_p = proc_nodes_touched[ elem->processor_id() ];
1836 for (
auto node : elem->node_index_range())
1837 set_p.insert(elem->node_id(node));
1843 <<
"] proc_nodes_touched contains "
1844 << proc_nodes_touched.size()
1845 <<
" sets of nodes."
1848 for (
const auto & [proc_id, set] : proc_nodes_touched)
1850 <<
"] proc_nodes_touched[" << proc_id <<
"] has "
1860 for (
auto & [proc_id, other_set] : proc_nodes_touched)
1866 std::set<unsigned int> this_intersection;
1869 std::set<unsigned> & my_set = proc_nodes_touched[this->
processor_id()];
1871 std::set_intersection(my_set.begin(), my_set.end(),
1872 other_set.begin(), other_set.end(),
1873 std::inserter(this_intersection, this_intersection.end()));
1875 if (!this_intersection.empty())
1877 (proc_id, std::move(this_intersection));
1884 <<
"] this->proc_nodes_touched_intersections[" << proc_id <<
"] has "
1903 std::set<unsigned> & other_set = pr.second;
1904 std::set<unsigned> intermediate_result;
1906 std::set_union(this->
border_node_ids.begin(), this->border_node_ids.end(),
1907 other_set.begin(), other_set.end(),
1908 std::inserter(intermediate_result, intermediate_result.end()));
1914 libmesh_assert_less_equal
1916 std::size_t(this->num_node_cmaps));
1942 std::map<boundary_id_type, std::vector<int>> local_node_boundary_id_lists;
1949 typedef std::tuple<dof_id_type, boundary_id_type> Tuple;
1950 std::vector<Tuple> bc_tuples =
mesh.get_boundary_info().build_node_list();
1955 << bc_tuples.size() << std::endl;
1957 for (
const auto & t : bc_tuples)
1958 libMesh::out <<
"(" << std::get<0>(t) <<
", " << std::get<1>(t) <<
") ";
1965 for (
const auto & t : bc_tuples)
1974 std::vector<int> & current_id_set = local_node_boundary_id_lists[std::get<1>(t)];
1978 current_id_set.push_back( it->second );
1985 for (
const auto & [bndry_id, set] : local_node_boundary_id_lists)
1990 for (
const auto &
id : set)
2004 const std::string & current_ns_name =
2005 mesh.get_boundary_info().get_nodeset_name
2006 (cast_int<boundary_id_type>(nodeset_id));
2015 <<
"] Writing out Exodus nodeset info for ID: " << nodeset_id
2016 <<
", Name: " << current_ns_name
2021 int exodus_id = nodeset_id;
2031 if (
const auto it = local_node_boundary_id_lists.find (cast_int<boundary_id_type>(nodeset_id));
2032 it == local_node_boundary_id_lists.end())
2037 <<
"] No nodeset data for ID: " << nodeset_id
2038 <<
" on this processor." << std::endl;
2041 this->
ex_err = exII::ex_put_node_set_param(this->
ex_id,
2045 EX_CHECK_ERR(this->
ex_err,
"Error writing nodeset parameters in Nemesis");
2051 const std::vector<int> & current_nodeset_ids = it->second;
2054 this->
ex_err = exII::ex_put_node_set_param(this->
ex_id,
2056 current_nodeset_ids.size(),
2059 EX_CHECK_ERR(this->
ex_err,
"Error writing nodeset parameters in Nemesis");
2064 current_nodeset_ids.data());
2066 EX_CHECK_ERR(this->
ex_err,
"Error writing nodesets in Nemesis");
2075 EX_CHECK_ERR(
ex_err,
"Error writing nodeset names");
2092 std::map<boundary_id_type, std::vector<int>> local_elem_boundary_id_lists;
2093 std::map<boundary_id_type, std::vector<int>> local_elem_boundary_id_side_lists;
2096 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> bndry_elem_side_id_list =
2097 mesh.get_boundary_info().build_side_list();
2100 for (
const auto & t : bndry_elem_side_id_list)
2103 const Elem * elem =
mesh.elem_ptr(std::get<0>(t));
2105 std::vector<const Elem *> family;
2106#ifdef LIBMESH_ENABLE_AMR
2113 family.push_back( elem );
2119 for (
const auto & tree_elem : family)
2122 const Elem & f =
mesh.elem_ref(f_id);
2135 local_elem_boundary_id_side_lists[ std::get<2>(t) ].push_back(conv.get_inverse_side_map( std::get<1>(t) ));
2149 const std::string & current_ss_name =
2150 mesh.get_boundary_info().get_sideset_name
2151 (cast_int<boundary_id_type>(exodus_id));
2160 <<
"] Writing out Exodus sideset info for ID: " << exodus_id
2161 <<
", Name: " << current_ss_name
2166 if (
const auto it = local_elem_boundary_id_lists.find (cast_int<boundary_id_type>(exodus_id));
2167 it == local_elem_boundary_id_lists.end())
2172 <<
"] No sideset data for ID: " << exodus_id
2173 <<
" on this processor." << std::endl;
2176 this->
ex_err = exII::ex_put_side_set_param(this->
ex_id,
2180 EX_CHECK_ERR(this->
ex_err,
"Error writing sideset parameters in Nemesis");
2186 const std::vector<int> & current_sideset_elem_ids = it->second;
2189 std::vector<int> & current_sideset_side_ids =
2190 libmesh_map_find(local_elem_boundary_id_side_lists,
2191 cast_int<boundary_id_type>(exodus_id));
2194 this->
ex_err = exII::ex_put_side_set_param(this->
ex_id,
2196 current_sideset_elem_ids.size(),
2199 EX_CHECK_ERR(this->
ex_err,
"Error writing sideset parameters in Nemesis");
2204 current_sideset_elem_ids.data(),
2205 current_sideset_side_ids.data());
2207 EX_CHECK_ERR(this->
ex_err,
"Error writing sidesets in Nemesis");
2217 EX_CHECK_ERR(
ex_err,
"Error writing sideset names");
2228 x.resize(local_num_nodes);
2229 y.resize(local_num_nodes);
2230 z.resize(local_num_nodes);
2241 if (local_num_nodes)
2244 ex_err = exII::ex_put_coord
2249 EX_CHECK_ERR(
ex_err,
"Error writing node coordinates");
2253 EX_CHECK_ERR(
ex_err,
"Error writing node num map");
2257 ex_err = exII::ex_put_coord(
ex_id,
nullptr,
nullptr,
nullptr);
2258 EX_CHECK_ERR(
ex_err,
"Error writing empty node coordinates");
2260 ex_err = exII::ex_put_node_num_map(
ex_id,
nullptr);
2261 EX_CHECK_ERR(
ex_err,
"Error writing empty node num map");
2288 (
mesh.subdomain_name(restrict_int<subdomain_id_type>(this->global_elem_blk_ids[i])));
2295 this->
ex_err = exII::ex_put_elem_block(this->
ex_id,
2302 EX_CHECK_ERR(this->
ex_err,
"Error writing element block from Nemesis.");
2309 cast_int<subdomain_id_type>(it->first);
2310 const std::vector<int> & this_block_connectivity = it->second;
2311 std::vector<dof_id_type> & elements_in_this_block =
subdomain_map[block];
2324 conv.exodus_elem_type().c_str(),
2325 elements_in_this_block.size(),
2328 EX_CHECK_ERR(
ex_err,
"Error writing element block from Nemesis.");
2332 this_block_connectivity.data());
2333 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities from Nemesis.");
2340 EX_CHECK_ERR(
ex_err,
"Error writing element map");
2344 EX_CHECK_ERR(
ex_err,
"Error writing element block names");
2353 const std::vector<std::string> & names,
2356 int num_vars = cast_int<int>(names.size());
2359 for (
int c=0; c<num_vars; c++)
2361#ifdef LIBMESH_USE_COMPLEX_NUMBERS
2362 std::vector<Real> real_parts(
num_nodes);
2363 std::vector<Real> imag_parts(
num_nodes);
2364 std::vector<Real> magnitudes(
num_nodes);
2369 real_parts[i] =
value.real();
2370 imag_parts[i] =
value.imag();
2371 magnitudes[i] = std::abs(
value);
2377 std::vector<Number> cur_soln(this->num_nodes);
2391 const std::vector<std::string> & names,
2393 const std::vector<std::string> & output_names)
2395 int num_vars = cast_int<int>(names.size());
2397 for (
int c=0; c<num_vars; c++)
2400 auto pos = std::find(output_names.begin(), output_names.end(), names[c]);
2403 if (pos == output_names.end())
2409 int variable_name_position =
2410 cast_int<int>(std::distance(output_names.begin(), pos));
2413 std::vector<numeric_index_type> required_indices(this->
num_nodes);
2420 std::vector<Number> local_soln;
2421 parallel_soln.
localize(local_soln, required_indices);
2423#ifndef LIBMESH_USE_COMPLEX_NUMBERS
2429 std::vector<Real> real_parts(
num_nodes);
2430 std::vector<Real> imag_parts(
num_nodes);
2431 std::vector<Real> magnitudes(
num_nodes);
2435 real_parts[i] = local_soln[i].real();
2436 imag_parts[i] = local_soln[i].imag();
2437 magnitudes[i] = std::abs(local_soln[i]);
2451 const std::vector<std::pair<unsigned int, unsigned int>> & var_nums,
2453 const std::vector<std::string> & output_names)
2460 for (
auto [sys_num, var] : var_nums)
2465 auto pos = std::find(output_names.begin(), output_names.end(), name);
2468 if (pos == output_names.end())
2474 int variable_name_position =
2475 cast_int<int>(std::distance(output_names.begin(), pos));
2478 std::vector<numeric_index_type> required_indices(this->
num_nodes);
2482 std::vector<Number> local_soln;
2487 std::vector<numeric_index_type> scalar_indices;
2490 required_indices[i] = scalar_indices[0];
2497 bool found_all_indices =
true;
2501 if (node.
n_comp(sys_num, var))
2502 required_indices[i] = node.
dof_number(sys_num, var, 0);
2505 found_all_indices =
false;
2510 if (found_all_indices)
2513 if (!found_all_indices)
2521 std::vector<Number> elem_soln;
2522 std::vector<Number> nodal_soln;
2523 std::vector<dof_id_type> dof_indices;
2525 for (
const auto & elem :
mesh.active_local_element_ptr_range())
2529 elem_soln.resize(dof_indices.size());
2532 elem_soln[i] = sys_soln(dof_indices[i]);
2541 if (!elem->infinite())
2542 for (
auto n : elem->node_index_range())
2544 const std::size_t exodus_num =
2546 libmesh_assert_greater(exodus_num, 0);
2547 libmesh_assert_less(exodus_num-1, local_soln.size());
2548 local_soln[exodus_num-1] = nodal_soln[n];
2554#ifndef LIBMESH_USE_COMPLEX_NUMBERS
2560 std::vector<Real> real_parts(
num_nodes);
2561 std::vector<Real> imag_parts(
num_nodes);
2562 std::vector<Real> magnitudes(
num_nodes);
2566 real_parts[i] = local_soln[i].real();
2567 imag_parts[i] = local_soln[i].imag();
2568 magnitudes[i] = std::abs(local_soln[i]);
2583 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
2586 if (names.size() == 0)
2612 if (vars_active_subdomains[var].empty() ||
2614 truth_tab[names.size() * blk + var] = 1;
2617 if (truth_tab.size())
2621 cast_int<int>(names.size()),
2623 EX_CHECK_ERR(
ex_err,
"Error writing element truth table.");
2632 const std::vector<std::pair<unsigned int, unsigned int>> &var_nums,
2634 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
2644 unsigned int var_ctr = 0;
2647 const unsigned int sys_num = var_nums[v].first;
2648 const unsigned int var = var_nums[v].second;
2656 const unsigned int n_comps =
2661 const auto & active_subdomains = vars_active_subdomains[v];
2666 restrict_int<subdomain_id_type>(sbd_id_int);
2668 const std::vector<dof_id_type> empty_vec;
2669 const std::vector<dof_id_type> & elem_ids =
2675 if ((active_subdomains.empty() || active_subdomains.count(sbd_id)) && elem_ids.size())
2677 std::vector<numeric_index_type> required_indices;
2678 required_indices.reserve(elem_ids.size());
2684 libmesh_assert_equal_to(n_comps,
mesh.elem_ref(elem_ids.back()).n_comp(sys_num, var));
2688 for (
unsigned int comp = 0; comp < n_comps; ++comp)
2690 for (
const auto &
id : elem_ids)
2691 required_indices.push_back(
mesh.elem_ref(
id).dof_number(sys_num, var, comp));
2693 std::vector<Number> local_soln;
2697 required_indices.clear();
2704 if (local_soln.size())
2706#ifdef LIBMESH_USE_COMPLEX_NUMBERS
2708 std::vector<Real> local_soln_buffer(local_soln.size());
2709 std::transform(local_soln.begin(), local_soln.end(),
2710 local_soln_buffer.begin(), [](
Number n) { return n.real(); });
2713 static_cast<int>(stride*(var_ctr+comp)+1),
2714 static_cast<int>(sbd_id),
2715 static_cast<int>(local_soln.size()),
2717 EX_CHECK_ERR(
ex_err,
"Error writing element real values.");
2719 std::transform(local_soln.begin(), local_soln.end(),
2720 local_soln_buffer.begin(), [](
Number n) { return n.imag(); });
2723 static_cast<int>(stride*(var_ctr+comp)+2),
2724 static_cast<int>(sbd_id),
2725 static_cast<int>(local_soln.size()),
2727 EX_CHECK_ERR(
ex_err,
"Error writing element imaginary values.");
2731 std::transform(local_soln.begin(), local_soln.end(),
2732 local_soln_buffer.begin(), [](
Number n) { return std::abs(n); });
2735 static_cast<int>(stride*(var_ctr+comp)+2),
2736 static_cast<int>(sbd_id),
2737 static_cast<int>(local_soln.size()),
2739 EX_CHECK_ERR(
ex_err,
"Error writing element magnitudes.");
2744 static_cast<int>(var_ctr+comp+1),
2745 static_cast<int>(sbd_id),
2746 static_cast<int>(local_soln.size()),
2748 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
2765 std::vector<std::string> & result)
2776 const std::size_t n_names = result.size();
2781 (n_names ?
nullptr : &n_names));
2783 this->
comm().
min(pid_broadcasting_names);
2795 std::ostringstream file_oss;
2814 unsigned int field_width = cast_int<unsigned int>(file_oss.str().size());
2817 libMesh::out <<
"field_width=" << field_width << std::endl;
2820 file_oss << base_filename
2822 <<
'.' << std::setfill(
'0') << std::setw(field_width) << this->
processor_id();
2825 return file_oss.str();
void min(const T &r, T &o, Request &req) const
void set_union(T &data, const unsigned int root_id) const
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
std::vector< NodeBCTuple > build_node_list(NodeBCTupleSortBy sort_by=NodeBCTupleSortBy::NODE_ID) const
const std::set< boundary_id_type > & get_node_boundary_ids() const
const std::set< boundary_id_type > & get_side_boundary_ids() const
This class handles the numbering of degrees of freedom on a mesh.
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
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...
unsigned int n_comp(const unsigned int s, const unsigned int var) const
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
processor_id_type processor_id() const
static constexpr processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
This is the base class from which all geometric element types are derived.
virtual unsigned int n_nodes() const =0
void active_family_tree_by_side(std::vector< const Elem * > &family, unsigned int side, bool reset=true) const
Same as the active_family_tree() member, but only adds elements which are next to side.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
virtual ElemType type() const =0
dof_id_type node_id(const unsigned int i) const
This is the EquationSystems class.
const MeshBase & get_mesh() const
const T_sys & get_system(std::string_view name) const
This class is useful for managing anything that requires a char ** input/output in ExodusII file.
void push_back_entry(const std::string &name)
Adds another name to the current data table.
char ** get_char_star_star()
Provide access to the underlying C data table.
This is the ExodusII_IO_Helper class.
void update()
Uses ex_update() to flush buffers to file.
std::vector< int > exodus_node_num_to_libmesh
unsigned _write_as_dimension
void close() noexcept
Closes the ExodusII mesh file.
bool _elem_vars_initialized
std::vector< int > num_nodes_per_set
void message(std::string_view msg)
Prints the message defined in msg.
void write_nodal_values(int var_id, const std::vector< Real > &values, int timestep)
Writes the vector of values to a nodal variable.
virtual void read_var_names_impl(const char *var_type, int &count, std::vector< std::string > &result)
read_var_names() dispatches to this function.
void write_var_names(ExodusVarType type, const std::vector< std::string > &names)
Wraps calls to exII::ex_put_var_names() and exII::ex_put_var_param().
std::vector< int > exodus_elem_num_to_libmesh
std::vector< std::string > elem_var_names
std::map< dof_id_type, dof_id_type > libmesh_elem_num_to_exodus
std::map< dof_id_type, dof_id_type > libmesh_node_num_to_exodus
std::vector< int > block_ids
void check_existing_vars(ExodusVarType type, std::vector< std::string > &names, std::vector< std::string > &names_from_file)
When appending: during initialization, check that variable names in the file match those you attempt ...
std::vector< int > nodeset_ids
bool _use_mesh_dimension_instead_of_spatial_dimension
const ExodusII_IO_Helper::Conversion & get_conversion(const ElemType type) const
std::vector< int > num_node_df_per_set
static unsigned int n_vec_dim(const MeshBase &mesh, const FEType &fe_type)
static FEFieldType field_type(const FEType &fe_type)
static void nodal_soln(const unsigned int dim, const FEType &fe_t, const Elem *elem, const std::vector< Number > &elem_soln, std::vector< Number > &nodal_soln, const bool add_p_level=true, const unsigned int vdim=1)
Build the nodal soln from the element soln.
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
FEFamily family
The type of finite element.
This is the MeshBase class.
virtual dof_id_type parallel_n_elem() const =0
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
virtual const Node * node_ptr(const dof_id_type i) const =0
unsigned int mesh_dimension() const
virtual const Elem & elem_ref(const dof_id_type i) const
virtual dof_id_type parallel_n_nodes() const =0
void compute_node_maps()
Compute the node maps (really just pack vectors) which map the nodes to internal, border,...
int num_border_elems
The number of border FEM elements.
std::vector< std::vector< int > > elem_cmap_proc_ids
void write_nodal_solution(const NumericVector< Number > ¶llel_soln, const std::vector< std::string > &names, int timestep, const std::vector< std::string > &output_names)
Takes a parallel solution vector containing the node-major solution vector for all variables and outp...
int num_external_nodes
The number of FEM nodes that reside on another processor but whose element partially resides on the c...
void put_node_map(std::vector< int > &node_mapi, std::vector< int > &node_mapb, std::vector< int > &node_mape)
Outputs IDs of internal, border, and external nodes.
virtual void write_nodal_coordinates(const MeshBase &mesh, bool use_discontinuous=false) override
This function is specialized from ExodusII_IO_Helper to write only the nodal coordinates stored on th...
virtual void write_sidesets(const MeshBase &mesh) override
Writes the sidesets for this processor.
void put_loadbal_param(unsigned num_internal_nodes, unsigned num_border_nodes, unsigned num_external_nodes, unsigned num_internal_elems, unsigned num_border_elems, unsigned num_node_cmaps, unsigned num_elem_cmaps)
Writes load balance parameters, some of which are described below: .) num_internal_nodes - nodes "who...
int num_internal_nodes
To be used with the Nemesis::ne_get_loadbal_param() routine.
void put_node_cmap(std::vector< std::vector< int > > &node_cmap_node_ids, std::vector< std::vector< int > > &node_cmap_proc_ids)
Outputs all of the nodal communication maps for this processor.
int num_internal_elems
The number of internal FEM elements.
void get_ss_param_global()
Fills: global_sideset_ids, num_global_side_counts, num_global_side_df_counts Call after: get_init_glo...
void put_ns_param_global(std::vector< int > &global_nodeset_ids, std::vector< int > &num_global_node_counts, std::vector< int > &num_global_node_df_counts)
This function writes information about global node sets.
std::set< unsigned > internal_elem_ids
A set of internal elem IDs for this processor.
char ftype
The type of file to be written.
void put_init_info(unsigned num_proc, unsigned num_proc_in_file, const char *ftype)
Writing functions.
std::map< unsigned, std::set< unsigned > > proc_nodes_touched_intersections
Another map to store sets of intersections with each other processor (other than ourself,...
void put_ss_param_global(std::vector< int > &global_sideset_ids, std::vector< int > &num_global_side_counts, std::vector< int > &num_global_side_df_counts)
This function writes information about global side sets.
std::vector< int > elem_cmap_elem_cnts
int num_border_nodes
The number of FEM nodes local to a processor but residing in an element which also has FEM nodes on o...
std::vector< int > elem_mapb
Vector which stores border element IDs.
std::vector< int > global_elem_blk_cnts
int num_proc_in_file
The number of processors for which the NEMESIS I file stores information.
void compute_communication_map_parameters()
This function determines the communication map parameters which will eventually be written to file.
void read_nodeset(int id)
Reading functions.
std::set< unsigned > border_elem_ids
A set of border elem IDs for this processor.
std::map< subdomain_id_type, unsigned > local_subdomain_counts
This map keeps track of the number of elements in each subdomain (block) for this processor.
std::map< subdomain_id_type, std::vector< dof_id_type > > subdomain_map
Map of subdomains to element numbers.
void compute_num_global_elem_blocks(const MeshBase &pmesh)
This function uses global communication routines to determine the number of element blocks across the...
void get_init_global()
Fills: num_nodes_global, num_elems_global, num_elem_blks_global, num_node_sets_global,...
int num_node_cmaps
The number of nodal communication maps for this processor.
std::set< int > nodes_attached_to_local_elems
libMesh numbered node ids attached to local elems.
std::set< unsigned > internal_node_ids
A set of internal node IDs for this processor.
void compute_num_global_nodesets(const MeshBase &pmesh)
This function uses global communication routines to determine the number of nodesets across the entir...
void put_elem_cmap(std::vector< std::vector< int > > &elem_cmap_elem_ids, std::vector< std::vector< int > > &elem_cmap_side_ids, std::vector< std::vector< int > > &elem_cmap_proc_ids)
Writes information about elemental communication map.
std::map< unsigned, std::set< unsigned > >::iterator proc_nodes_touched_iterator
Typedef for an iterator into the data structure above.
std::vector< int > num_global_side_df_counts
std::vector< int > elem_mapi
Vector which stores internal element IDs.
void write_exodus_initialization_info(const MeshBase &pmesh, const std::string &title)
This function writes exodus-specific initialization information.
void compute_elem_communication_maps()
This function computes element communication maps (really just packs vectors) in preparation for writ...
std::vector< int > num_global_side_counts
int nemesis_err_flag
Member data.
void compute_element_maps()
This function computes element maps (really just packs vectors) which map the elements to internal an...
std::vector< int > node_mape
Vector which stores external node IDs.
Nemesis_IO_Helper(const ParallelObject &parent, bool verbose=false, bool single_precision=false)
Constructor.
std::vector< int > node_mapb
Vector which stores border node IDs.
std::vector< int > node_cmap_node_cnts
std::vector< int > node_cmap_ids
Vectors for storing the communication map parameters.
void put_elem_map(std::vector< int > &elem_mapi, std::vector< int > &elem_mapb)
Outputs IDs of internal and border elements.
int num_nodes_global
Global initial information.
virtual void initialize_element_variables(std::vector< std::string > names, const std::vector< std::set< subdomain_id_type > > &vars_active_subdomains) override
Override the Exodus Helper's implementation of this function so that it works correctly in parallel.
std::vector< int > global_elem_blk_ids
Read the global element block IDs and counts.
std::vector< int > node_list
void compute_internal_and_border_elems_and_internal_nodes(const MeshBase &pmesh)
This function constructs the set of border and internal element IDs and internal node IDs present on ...
void get_ns_param_global()
std::vector< int > num_global_node_df_counts
std::vector< std::vector< int > > node_cmap_proc_ids
void compute_num_global_sidesets(const MeshBase &pmesh)
This function uses global communication routines to determine the number of sidesets across the entir...
std::map< int, std::vector< int > > block_id_to_elem_connectivity
This is the block connectivity, i.e.
std::vector< int > global_nodeset_ids
Containers for reading global nodeset information.
std::vector< std::vector< int > > elem_cmap_elem_ids
3 vectors of vectors for storing element communication IDs for this processor.
void put_cmap_params(std::vector< int > &node_cmap_ids, std::vector< int > &node_cmap_node_cnts, std::vector< int > &elem_cmap_ids, std::vector< int > &elem_cmap_elem_cnts)
Outputs initial information for communication maps.
void get_eb_info_global()
std::vector< int > num_global_node_counts
void compute_border_node_ids(const MeshBase &pmesh)
This function constructs the set of border node IDs present on the current mesh.
void build_element_and_node_maps(const MeshBase &pmesh)
This function builds the libmesh -> exodus and exodus -> libmesh node and element maps.
bool write_complex_abs
By default, when complex numbers are enabled, for each variable we write out three values: the real p...
void put_eb_info_global(std::vector< int > &global_elem_blk_ids, std::vector< int > &global_elem_blk_cnts)
Writes global block information to the file .) global_elem_blk_ids - list of block IDs for all blocks...
void put_init_global(dof_id_type num_nodes_global, dof_id_type num_elems_global, unsigned num_elem_blks_global, unsigned num_node_sets_global, unsigned num_side_sets_global)
Writes global information including: .) global number of nodes .) global number of elems ....
std::vector< int > node_mapi
Vector which stores internal node IDs.
int num_elem_cmaps
The number of elemental communication maps for this processor.
void compute_node_communication_maps()
Compute the node communication maps (really just pack vectors) in preparation for writing them to fil...
virtual void initialize(std::string title, const MeshBase &mesh, bool use_discontinuous=false) override
Specialization of the initialize function from ExodusII_IO_Helper that also writes global initial dat...
std::set< unsigned > border_node_ids
The set which will eventually contain the IDs of "border nodes".
std::vector< int > elem_cmap_ids
std::vector< std::vector< int > > elem_cmap_side_ids
std::map< unsigned, std::set< std::pair< unsigned, unsigned > > >::iterator proc_border_elem_sets_iterator
Typedef for an iterator into the data structure above.
std::string construct_nemesis_filename(std::string_view base_filename)
Given base_filename, foo.e, constructs the Nemesis filename foo.e.X.Y, where X=n.
void write_element_values(const MeshBase &mesh, const EquationSystems &es, const std::vector< std::pair< unsigned int, unsigned int > > &var_nums, int timestep, const std::vector< std::set< subdomain_id_type > > &vars_active_subdomains)
Writes the vector of elemental variable values, one variable and one subdomain at a time.
virtual void write_elements(const MeshBase &mesh, bool use_discontinuous=false) override
This function is specialized to write the connectivity.
std::vector< std::vector< int > > node_cmap_node_ids
2 vectors of vectors for storing the node communication IDs for this processor.
virtual ~Nemesis_IO_Helper()
Destructor.
int num_proc
The number of processors for which the NEMESIS I file was created.
std::vector< int > global_sideset_ids
Containers for reading global sideset (boundary conditions) information.
virtual void write_nodesets(const MeshBase &mesh) override
Writes the nodesets for this processor.
std::map< unsigned, std::set< std::pair< unsigned, unsigned > > > proc_border_elem_sets
Map between processor ID and (element,side) pairs bordering that processor ID.
virtual void read_var_names_impl(const char *var_type, int &count, std::vector< std::string > &result) override
read_var_names() dispatches to this function.
A Node is like a Point, but with more information.
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual void localize(std::vector< T > &v_local) const =0
Creates a copy of the global vector in the local vector v_local.
An object whose state is distributed along a set of processors.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Manages consistently variables, degrees of freedom, and coefficient vectors.
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
const Variable & variable(unsigned int var) const
Return a constant reference to Variable var.
const FEType & variable_type(const unsigned int i) const
const std::string & variable_name(const unsigned int i) const
const DofMap & get_dof_map() const
This class defines the notion of a variable in the system.
bool active_on_subdomain(subdomain_id_type sid) const
The libMesh namespace provides an interface to certain functionality in the library.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
uint8_t processor_id_type
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
This class facilitates inline conversion of an input data vector to a different precision level,...