exodusII_io_helper.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2014 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 
20 
21 
22 #ifdef LIBMESH_HAVE_EXODUS_API
23 
24 #include <algorithm>
25 #include <functional>
26 
27 #include "libmesh/boundary_info.h"
28 #include "libmesh/enum_elem_type.h"
29 #include "libmesh/elem.h"
30 #include "libmesh/system.h"
31 #include "libmesh/numeric_vector.h"
32 #include "libmesh/string_to_enum.h"
33 
34 #ifdef DEBUG
35 #include "libmesh/mesh_tools.h" // for elem_types warning
36 #endif
37 
38 // This macro returns the length of the array a. Don't
39 // try using it on empty arrays, since it accesses the
40 // zero'th element.
41 #define ARRAY_LENGTH(a) (sizeof((a))/sizeof((a)[0]))
42 
43 // Anonymous namespace for file local data
44 namespace
45 {
46  // Define equivalence classes of Cubit/Exodus element types that map to
47  // libmesh ElemTypes
48  std::map<std::string, libMeshEnums::ElemType> element_equivalence_map;
49 
50  // This function initializes the element_equivalence_map the first time it
51  // is called, and returns early all other times.
52  void init_element_equivalence_map()
53  {
54  if (element_equivalence_map.empty())
55  {
56  // EDGE2 equivalences
57  element_equivalence_map["EDGE2"] = EDGE2;
58  element_equivalence_map["TRUSS"] = EDGE2;
59  element_equivalence_map["BEAM"] = EDGE2;
60  element_equivalence_map["BAR"] = EDGE2;
61  element_equivalence_map["TRUSS2"] = EDGE2;
62  element_equivalence_map["BEAM2"] = EDGE2;
63  element_equivalence_map["BAR2"] = EDGE2;
64 
65  // EDGE3 equivalences
66  element_equivalence_map["EDGE3"] = EDGE3;
67  element_equivalence_map["TRUSS3"] = EDGE3;
68  element_equivalence_map["BEAM3"] = EDGE3;
69  element_equivalence_map["BAR3"] = EDGE3;
70 
71  // QUAD4 equivalences
72  element_equivalence_map["QUAD"] = QUAD4;
73  element_equivalence_map["QUAD4"] = QUAD4;
74  // element_equivalence_map["SHELL"] = QUAD4;
75  // element_equivalence_map["SHELL4"] = QUAD4;
76 
77  // QUAD8 equivalences
78  element_equivalence_map["QUAD8"] = QUAD8;
79  // element_equivalence_map["SHELL8"] = QUAD8;
80 
81  // QUAD9 equivalences
82  element_equivalence_map["QUAD9"] = QUAD9;
83  // element_equivalence_map["SHELL9"] = QUAD9;
84 
85  // TRI3 equivalences
86  element_equivalence_map["TRI"] = TRI3;
87  element_equivalence_map["TRI3"] = TRI3;
88  element_equivalence_map["TRIANGLE"] = TRI3;
89  // element_equivalence_map["TRISHELL"] = TRI3;
90  // element_equivalence_map["TRISHELL3"] = TRI3;
91 
92  // TRI6 equivalences
93  element_equivalence_map["TRI6"] = TRI6;
94  // element_equivalence_map["TRISHELL6"] = TRI6;
95 
96  // HEX8 equivalences
97  element_equivalence_map["HEX"] = HEX8;
98  element_equivalence_map["HEX8"] = HEX8;
99 
100  // HEX20 equivalences
101  element_equivalence_map["HEX20"] = HEX20;
102 
103  // HEX27 equivalences
104  element_equivalence_map["HEX27"] = HEX27;
105 
106  // TET4 equivalences
107  element_equivalence_map["TETRA"] = TET4;
108  element_equivalence_map["TETRA4"] = TET4;
109 
110  // TET10 equivalences
111  element_equivalence_map["TETRA10"] = TET10;
112 
113  // PRISM6 equivalences
114  element_equivalence_map["WEDGE"] = PRISM6;
115 
116  // PRISM15 equivalences
117  element_equivalence_map["WEDGE15"] = PRISM15;
118 
119  // PRISM18 equivalences
120  element_equivalence_map["WEDGE18"] = PRISM18;
121 
122  // PYRAMID5 equivalences
123  element_equivalence_map["PYRAMID"] = PYRAMID5;
124  element_equivalence_map["PYRAMID5"] = PYRAMID5;
125 
126  // PYRAMID14 equivalences
127  element_equivalence_map["PYRAMID14"] = PYRAMID14;
128  }
129  }
130 }
131 
132 
133 
134 namespace libMesh
135 {
136 
137 // ------------------------------------------------------------
138 // ExodusII_IO_Helper::ElementMaps static data
139 
140 // 1D node map definitions
142 const int ExodusII_IO_Helper::ElementMaps::edge3_node_map[3] = {0, 1, 2};
143 
144 // 1D edge maps
145 // FIXME: This notion may or may not be defined in ExodusII
148 
149 // 2D node map definitions
150 const int ExodusII_IO_Helper::ElementMaps::quad4_node_map[4] = {0, 1, 2, 3};
151 const int ExodusII_IO_Helper::ElementMaps::quad8_node_map[8] = {0, 1, 2, 3, 4, 5, 6, 7};
152 const int ExodusII_IO_Helper::ElementMaps::quad9_node_map[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
153 const int ExodusII_IO_Helper::ElementMaps::tri3_node_map[3] = {0, 1, 2};
154 const int ExodusII_IO_Helper::ElementMaps::tri6_node_map[6] = {0, 1, 2, 3, 4, 5};
155 
156 // 2D edge map definitions
157 const int ExodusII_IO_Helper::ElementMaps::tri_edge_map[3] = {0, 1, 2};
158 const int ExodusII_IO_Helper::ElementMaps::quad_edge_map[4] = {0, 1, 2, 3};
159 
160 //These take a libMesh ID and turn it into an Exodus ID
163 
164 // 3D node map definitions
165 const int ExodusII_IO_Helper::ElementMaps::hex8_node_map[8] = {0, 1, 2, 3, 4, 5, 6, 7};
166 const int ExodusII_IO_Helper::ElementMaps::hex20_node_map[20] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
167  10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
168 
169 // Perhaps an older Hex27 node numbering? This no longer works.
170 //const int ExodusII_IO_Helper::ElementMaps::hex27_node_map[27] = { 1, 5, 6, 2, 0, 4, 7, 3, 13, 17, 14, 9, 8, 16,
171 // 18, 10, 12, 19, 15, 11, 24, 25, 22, 26, 21, 23, 20};
172 
173 //DRG: Using the newest exodus documentation available on sourceforge and using Table 2 to see
174 // where all of the nodes over 21 are supposed to go... we come up with:
176  // Vertex and mid-edge nodes
177  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
178  // Mid-face nodes and centroid
179  21, 25, 24, 26, 23, 22, 20};
180 //20 21 22 23 24 25 26 // LibMesh indices
181 
182 // The hex27 appears to be the only element without a 1:1 map between its
183 // node numbering and libmesh's. Therefore when writing out hex27's we need
184 // to invert this map...
186  // Vertex and mid-edge nodes
187  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
188  // Mid-face nodes and centroid
189  26, 20, 25, 24, 22, 21, 23};
190 //20 21 22 23 24 25 26
191 
192 
193 const int ExodusII_IO_Helper::ElementMaps::tet4_node_map[4] = {0, 1, 2, 3};
194 const int ExodusII_IO_Helper::ElementMaps::tet10_node_map[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
195 
196 const int ExodusII_IO_Helper::ElementMaps::prism6_node_map[6] = {0, 1, 2, 3, 4, 5};
197 const int ExodusII_IO_Helper::ElementMaps::prism15_node_map[15] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
198  10, 11, 12, 13, 14};
199 const int ExodusII_IO_Helper::ElementMaps::prism18_node_map[18] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
200  10, 11, 12, 13, 14, 15, 16, 17};
201 const int ExodusII_IO_Helper::ElementMaps::pyramid5_node_map[5] = {0, 1, 2, 3, 4};
202 const int ExodusII_IO_Helper::ElementMaps::pyramid14_node_map[14] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
203 
204 // 3D face map definitions
205 const int ExodusII_IO_Helper::ElementMaps::tet_face_map[4] = {1, 2, 3, 0};
206 
207 const int ExodusII_IO_Helper::ElementMaps::hex_face_map[6] = {1, 2, 3, 4, 0, 5};
208 const int ExodusII_IO_Helper::ElementMaps::hex27_face_map[6] = {1, 2, 3, 4, 0, 5};
209 //const int ExodusII_IO_Helper::ElementMaps::hex27_face_map[6] = {1, 0, 3, 5, 4, 2};
210 const int ExodusII_IO_Helper::ElementMaps::prism_face_map[5] = {1, 2, 3, 0, 4};
211 const int ExodusII_IO_Helper::ElementMaps::pyramid_face_map[5] = {-1,-1,-1,-1,-1}; // Not Implemented!
212 
213 //These take a libMesh ID and turn it into an Exodus ID
215 const int ExodusII_IO_Helper::ElementMaps::hex_inverse_face_map[6] = {5, 1, 2, 3, 4, 6};
216 const int ExodusII_IO_Helper::ElementMaps::hex27_inverse_face_map[6] = {5, 1, 2, 3, 4, 6};
217 //const int ExodusII_IO_Helper::ElementMaps::hex27_inverse_face_map[6] = {2, 1, 6, 3, 5, 4};
218 const int ExodusII_IO_Helper::ElementMaps::prism_inverse_face_map[5] = {4, 1, 2, 3, 5};
219 const int ExodusII_IO_Helper::ElementMaps::pyramid_inverse_face_map[5] = {-1,-1,-1,-1,-1}; // Not Implemented!
220 
221 
222 // ------------------------------------------------------------
223 // ExodusII_IO_Helper class members
224 
226  bool v,
227  bool run_only_on_proc0) :
228  ParallelObject(parent),
229  ex_id(0),
230  ex_err(0),
231  num_dim(0),
232  num_global_vars(0),
233  num_nodes(0),
234  num_elem(0),
235  num_elem_blk(0),
236  num_node_sets(0),
237  num_side_sets(0),
238  num_elem_this_blk(0),
239  num_nodes_per_elem(0),
240  num_attr(0),
241  num_elem_all_sidesets(0),
242  num_time_steps(0),
243  num_nodal_vars(0),
244  num_elem_vars(0),
245  verbose(v),
246  opened_for_writing(false),
247  opened_for_reading(false),
248  _run_only_on_proc0(run_only_on_proc0),
249  _elem_vars_initialized(false),
250  _global_vars_initialized(false),
251  _nodal_vars_initialized(false),
252  _use_mesh_dimension_instead_of_spatial_dimension(false)
253  {
254  title.resize(MAX_LINE_LENGTH+1);
255  elem_type.resize(MAX_STR_LENGTH);
256  }
257 
258 
259 
261 {
262 }
263 
264 
265 
267 {
268  return &elem_type[0];
269 }
270 
271 
272 
273 void ExodusII_IO_Helper::message(const std::string msg)
274 {
275  if (verbose) libMesh::out << msg << std::endl;
276 }
277 
278 
279 
280 void ExodusII_IO_Helper::message(const std::string msg, int i)
281 {
282  if (verbose) libMesh::out << msg << i << "." << std::endl;
283 }
284 
285 
286 
287 void ExodusII_IO_Helper::open(const char* filename, bool read_only)
288 {
289  // Version of Exodus you are using
290  float ex_version = 0.;
291 
292  // Word size in bytes of the floating point variables used in the
293  // application program (0, 4, or 8)
294  int comp_ws = sizeof(Real);
295 
296  // Word size in bytes of the floating point data as they are stored
297  // in the ExodusII file. "If this argument is 0, the word size of the
298  // floating point data already stored in the file is returned"
299  int io_ws = 0;
300 
301  ex_id = exII::ex_open(filename,
302  read_only ? EX_READ : EX_WRITE,
303  &comp_ws,
304  &io_ws,
305  &ex_version);
306 
307  std::string err_msg = std::string("Error opening ExodusII mesh file: ") + std::string(filename);
308  EX_CHECK_ERR(ex_id, err_msg);
309  if (verbose) libMesh::out << "File opened successfully." << std::endl;
310 
311  if (read_only)
312  opened_for_reading = true;
313  else
314  opened_for_writing = true;
315 
316  current_filename = std::string(filename);
317 }
318 
319 
320 
322 {
324  &title[0],
325  &num_dim,
326  &num_nodes,
327  &num_elem,
328  &num_elem_blk,
329  &num_node_sets,
330  &num_side_sets);
331 
332  EX_CHECK_ERR(ex_err, "Error retrieving header info.");
333 
334  this->read_num_time_steps();
335 
337  EX_CHECK_ERR(ex_err, "Error reading number of nodal variables.");
338 
340  EX_CHECK_ERR(ex_err, "Error reading number of elemental variables.");
341 
343  EX_CHECK_ERR(ex_err, "Error reading number of global variables.");
344 
345  message("Exodus header info retrieved successfully.");
346 }
347 
348 
349 
350 
352 {
353  if (verbose)
354  libMesh::out << "Title: \t" << &title[0] << std::endl
355  << "Mesh Dimension: \t" << num_dim << std::endl
356  << "Number of Nodes: \t" << num_nodes << std::endl
357  << "Number of elements: \t" << num_elem << std::endl
358  << "Number of elt blocks: \t" << num_elem_blk << std::endl
359  << "Number of node sets: \t" << num_node_sets << std::endl
360  << "Number of side sets: \t" << num_side_sets << std::endl;
361 }
362 
363 
364 
366 {
367  x.resize(num_nodes);
368  y.resize(num_nodes);
369  z.resize(num_nodes);
370 
372  static_cast<void*>(&x[0]),
373  static_cast<void*>(&y[0]),
374  static_cast<void*>(&z[0]));
375 
376  EX_CHECK_ERR(ex_err, "Error retrieving nodal data.");
377  message("Nodal data retrieved successfully.");
378 }
379 
380 
381 
383 {
384  node_num_map.resize(num_nodes);
385 
387  node_num_map.empty() ? NULL : &node_num_map[0]);
388 
389  EX_CHECK_ERR(ex_err, "Error retrieving nodal number map.");
390  message("Nodal numbering map retrieved successfully.");
391 
392  if (verbose)
393  {
394  libMesh::out << "[" << this->processor_id() << "] node_num_map[i] = ";
395  for (unsigned int i=0; i<static_cast<unsigned int>(std::min(10, num_nodes-1)); ++i)
396  libMesh::out << node_num_map[i] << ", ";
397  libMesh::out << "... " << node_num_map.back() << std::endl;
398  }
399 }
400 
401 
402 void ExodusII_IO_Helper::print_nodes(std::ostream &out_stream)
403 {
404  for (int i=0; i<num_nodes; i++)
405  out_stream << "(" << x[i] << ", " << y[i] << ", " << z[i] << ")" << std::endl;
406 }
407 
408 
409 
411 {
412  block_ids.resize(num_elem_blk);
413  // Get all element block IDs.
415  block_ids.empty() ? NULL : &block_ids[0]);
416  // Usually, there is only one
417  // block since there is only
418  // one type of element.
419  // However, there could be more.
420 
421  EX_CHECK_ERR(ex_err, "Error getting block IDs.");
422  message("All block IDs retrieved successfully.");
423 
424  char name_buffer[MAX_STR_LENGTH+1];
425  for (int i=0; i<num_elem_blk; ++i)
426  {
428  block_ids[i], name_buffer);
429  EX_CHECK_ERR(ex_err, "Error getting block name.");
430  id_to_block_names[block_ids[i]] = name_buffer;
431  }
432  message("All block names retrieved successfully.");
433 }
434 
435 
436 
438 {
439  libmesh_assert_less (static_cast<unsigned int>(index), block_ids.size());
440 
441  return block_ids[index];
442 }
443 
444 
445 
447 {
448  libmesh_assert_less (static_cast<unsigned int>(index), block_ids.size());
449 
450  return id_to_block_names[block_ids[index]];
451 }
452 
453 
454 
456 {
457  libmesh_assert_less (static_cast<unsigned int>(index), ss_ids.size());
458 
459  return ss_ids[index];
460 }
461 
462 
463 
465 {
466  libmesh_assert_less (static_cast<unsigned int>(index), ss_ids.size());
467 
468  return id_to_ss_names[ss_ids[index]];
469 }
470 
471 
472 
474 {
475  libmesh_assert_less (static_cast<unsigned int>(index), nodeset_ids.size());
476 
477  return nodeset_ids[index];
478 }
479 
480 
481 
483 {
484  libmesh_assert_less (static_cast<unsigned int>(index), nodeset_ids.size());
485 
486  return id_to_ns_names[nodeset_ids[index]];
487 }
488 
489 
490 
491 
493 {
494  libmesh_assert_less (static_cast<unsigned int>(block), block_ids.size());
495 
497  block_ids[block],
498  &elem_type[0],
501  &num_attr);
502  if (verbose)
503  libMesh::out << "Reading a block of " << num_elem_this_blk
504  << " " << &elem_type[0] << "(s)"
505  << " having " << num_nodes_per_elem
506  << " nodes per element." << std::endl;
507 
508  EX_CHECK_ERR(ex_err, "Error getting block info.");
509  message("Info retrieved successfully for block: ", block);
510 
511 
512 
513  // Read in the connectivity of the elements of this block,
514  // watching out for the case where we actually have no
515  // elements in this block (possible with parallel files)
517 
518  if (!connect.empty())
519  {
520  ex_err = exII::ex_get_elem_conn(ex_id,
521  block_ids[block],
522  &connect[0]);
523 
524  EX_CHECK_ERR(ex_err, "Error reading block connectivity.");
525  message("Connectivity retrieved successfully for block: ", block);
526  }
527 }
528 
529 
530 
531 
533 {
534  elem_num_map.resize(num_elem);
535 
537  elem_num_map.empty() ? NULL : &elem_num_map[0]);
538 
539  EX_CHECK_ERR(ex_err, "Error retrieving element number map.");
540  message("Element numbering map retrieved successfully.");
541 
542 
543  if (verbose)
544  {
545  libMesh::out << "[" << this->processor_id() << "] elem_num_map[i] = ";
546  for (unsigned int i=0; i<static_cast<unsigned int>(std::min(10, num_elem-1)); ++i)
547  libMesh::out << elem_num_map[i] << ", ";
548  libMesh::out << "... " << elem_num_map.back() << std::endl;
549  }
550 }
551 
552 
553 
555 {
556  ss_ids.resize(num_side_sets);
557  if (num_side_sets > 0)
558  {
560  &ss_ids[0]);
561  EX_CHECK_ERR(ex_err, "Error retrieving sideset information.");
562  message("All sideset information retrieved successfully.");
563 
564  // Resize appropriate data structures -- only do this once outside the loop
567 
568  // Inquire about the length of the concatenated side sets element list
569  num_elem_all_sidesets = inquire(exII::EX_INQ_SS_ELEM_LEN, "Error retrieving length of the concatenated side sets element list!");
570 
574  }
575 
576  char name_buffer[MAX_STR_LENGTH+1];
577  for (int i=0; i<num_side_sets; ++i)
578  {
580  ss_ids[i], name_buffer);
581  EX_CHECK_ERR(ex_err, "Error getting side set name.");
582  id_to_ss_names[ss_ids[i]] = name_buffer;
583  }
584  message("All side set names retrieved successfully.");
585 }
586 
588 {
589  nodeset_ids.resize(num_node_sets);
590  if (num_node_sets > 0)
591  {
593  &nodeset_ids[0]);
594  EX_CHECK_ERR(ex_err, "Error retrieving nodeset information.");
595  message("All nodeset information retrieved successfully.");
596 
597  // Resize appropriate data structures -- only do this once outnode the loop
600  }
601 
602  char name_buffer[MAX_STR_LENGTH+1];
603  for (int i=0; i<num_node_sets; ++i)
604  {
606  nodeset_ids[i], name_buffer);
607  EX_CHECK_ERR(ex_err, "Error getting node set name.");
608  id_to_ns_names[nodeset_ids[i]] = name_buffer;
609  }
610  message("All node set names retrieved successfully.");
611 }
612 
613 
614 
615 void ExodusII_IO_Helper::read_sideset(int id, int offset)
616 {
617  libmesh_assert_less (static_cast<unsigned int>(id), ss_ids.size());
618  libmesh_assert_less (static_cast<unsigned int>(id), num_sides_per_set.size());
619  libmesh_assert_less (static_cast<unsigned int>(id), num_df_per_set.size());
620  libmesh_assert_less_equal (static_cast<unsigned int>(offset), elem_list.size());
621  libmesh_assert_less_equal (static_cast<unsigned int>(offset), side_list.size());
622 
624  ss_ids[id],
625  &num_sides_per_set[id],
626  &num_df_per_set[id]);
627  EX_CHECK_ERR(ex_err, "Error retrieving sideset parameters.");
628  message("Parameters retrieved successfully for sideset: ", id);
629 
630 
631  // It's OK for offset==elem_list.size() as long as num_sides_per_set[id]==0
632  // because in that case we don't actually read anything...
633 #ifdef DEBUG
634  if (static_cast<unsigned int>(offset) == elem_list.size() ||
635  static_cast<unsigned int>(offset) == side_list.size() )
636  libmesh_assert_equal_to (num_sides_per_set[id], 0);
637 #endif
638 
639 
640  // Don't call ex_get_side_set unless there are actually sides there to get.
641  // Exodus prints an annoying warning in DEBUG mode otherwise...
642  if (num_sides_per_set[id] > 0)
643  {
644  ex_err = exII::ex_get_side_set(ex_id,
645  ss_ids[id],
646  &elem_list[offset],
647  &side_list[offset]);
648  EX_CHECK_ERR(ex_err, "Error retrieving sideset data.");
649  message("Data retrieved successfully for sideset: ", id);
650 
651  for (int i=0; i<num_sides_per_set[id]; i++)
652  id_list[i+offset] = ss_ids[id];
653  }
654 }
655 
656 
657 
659 {
660  libmesh_assert_less (static_cast<unsigned int>(id), nodeset_ids.size());
661  libmesh_assert_less (static_cast<unsigned int>(id), num_nodes_per_set.size());
662  libmesh_assert_less (static_cast<unsigned int>(id), num_node_df_per_set.size());
663 
665  nodeset_ids[id],
666  &num_nodes_per_set[id],
667  &num_node_df_per_set[id]);
668  EX_CHECK_ERR(ex_err, "Error retrieving nodeset parameters.");
669  message("Parameters retrieved successfully for nodeset: ", id);
670 
671  node_list.resize(num_nodes_per_set[id]);
672 
673  // Don't call ex_get_node_set unless there are actually nodes there to get.
674  // Exodus prints an annoying warning message in DEBUG mode otherwise...
675  if (num_nodes_per_set[id] > 0)
676  {
677  ex_err = exII::ex_get_node_set(ex_id,
678  nodeset_ids[id],
679  &node_list[0]);
680 
681  EX_CHECK_ERR(ex_err, "Error retrieving nodeset data.");
682  message("Data retrieved successfully for nodeset: ", id);
683  }
684 }
685 
686 
687 
689 {
690  // Always call close on processor 0.
691  // If we're running on multiple processors, i.e. as one of several Nemesis files,
692  // we call close on all processors...
693  if ((this->processor_id() == 0) || (!_run_only_on_proc0))
694  {
696  EX_CHECK_ERR(ex_err, "Error closing Exodus file.");
697  message("Exodus file closed successfully.");
698  }
699 }
700 
701 
702 
703 int ExodusII_IO_Helper::inquire(int req_info_in, std::string error_msg)
704 {
705  int ret_int = 0;
706  char ret_char = 0;
707  float ret_float = 0.;
708 
710  req_info_in,
711  &ret_int,
712  &ret_float,
713  &ret_char);
714 
715  EX_CHECK_ERR(ex_err, error_msg);
716 
717  return ret_int;
718 }
719 
720 
721 
723 {
724  // Make sure we have an up-to-date count of the number of time steps in the file.
725  this->read_num_time_steps();
726 
727  if (num_time_steps > 0)
728  {
729  time_steps.resize(num_time_steps);
731  EX_CHECK_ERR(ex_err, "Error reading timesteps!");
732  }
733 }
734 
735 
736 
738 {
740  this->inquire(exII::EX_INQ_TIME, "Error retrieving number of time steps");
741 }
742 
743 
744 
745 void ExodusII_IO_Helper::read_nodal_var_values(std::string nodal_var_name, int time_step)
746 {
747  // Read the nodal variable names from file, so we can see if we have the one we're looking for
748  this->read_var_names(NODAL);
749 
750  // See if we can find the variable we are looking for
751  unsigned int var_index = 0;
752  bool found = false;
753 
754  // Do a linear search for nodal_var_name in nodal_var_names
755  for (; var_index<nodal_var_names.size(); ++var_index)
756  {
757  found = (nodal_var_names[var_index] == nodal_var_name);
758  if (found)
759  break;
760  }
761 
762  if (!found)
763  {
764  libMesh::err << "Unable to locate variable named: " << nodal_var_name << std::endl;
765  libMesh::err << "Available variables: " << std::endl;
766  for (unsigned int i=0; i<nodal_var_names.size(); ++i)
767  libMesh::err << nodal_var_names[i] << std::endl;
768 
769  libmesh_error();
770  }
771 
772  // Allocate enough space to store the nodal variable values
773  nodal_var_values.resize(num_nodes);
774 
775  // Call the Exodus API to read the nodal variable values
777  time_step,
778  var_index+1,
779  num_nodes,
780  &nodal_var_values[0]);
781  EX_CHECK_ERR(ex_err, "Error reading nodal variable values!");
782 }
783 
784 
785 
787 {
788  switch (type)
789  {
790  case NODAL:
792  break;
793  case ELEMENTAL:
795  break;
796  case GLOBAL:
798  break;
799  default:
800  libMesh::err << "Unrecognized ExodusVarType " << type << std::endl;
801  libmesh_error();
802  }
803 }
804 
805 
806 
807 void ExodusII_IO_Helper::read_var_names_impl(const char* var_type,
808  int& count,
809  std::vector<std::string>& result)
810 {
811  // First read and store the number of names we have
812  ex_err = exII::ex_get_var_param(ex_id, var_type, &count);
813  EX_CHECK_ERR(ex_err, "Error reading number of variables.");
814 
815  // Second read the actual names and convert them into a format we can use
816  NamesData names_table(count, MAX_STR_LENGTH);
817 
819  var_type,
820  count,
821  names_table.get_char_star_star()
822  );
823  EX_CHECK_ERR(ex_err, "Error reading variable names!");
824 
825  if (verbose)
826  {
827  libMesh::out << "Read the variable(s) from the file:" << std::endl;
828  for (int i=0; i<count; i++)
829  libMesh::out << names_table.get_char_star(i) << std::endl;
830  }
831 
832  // Allocate enough space for our variable name strings.
833  result.resize(count);
834 
835  // Copy the char buffers into strings.
836  for (int i=0; i<count; i++)
837  result[i] = names_table.get_char_star(i); // calls string::op=(const char*)
838 }
839 
840 
841 
842 
843 void ExodusII_IO_Helper::write_var_names(ExodusVarType type, std::vector<std::string>& names)
844 {
845  switch (type)
846  {
847  case NODAL:
848  this->write_var_names_impl("n", num_nodal_vars, names);
849  break;
850  case ELEMENTAL:
851  this->write_var_names_impl("e", num_elem_vars, names);
852  break;
853  case GLOBAL:
854  this->write_var_names_impl("g", num_global_vars, names);
855  break;
856  default:
857  libMesh::err << "Unrecognized ExodusVarType " << type << std::endl;
858  libmesh_error();
859  }
860 }
861 
862 
863 
864 void ExodusII_IO_Helper::write_var_names_impl(const char* var_type, int& count, std::vector<std::string>& names)
865 {
866  // Update the count variable so that it's available to other parts of the class.
867  count = names.size();
868 
869  // Write that number of variables to the file.
870  ex_err = exII::ex_put_var_param(ex_id, var_type, count);
871  EX_CHECK_ERR(ex_err, "Error setting number of vars.");
872 
873  if (names.size() > 0)
874  {
875  NamesData names_table(names.size(), MAX_STR_LENGTH);
876 
877  // Store the input names in the format required by Exodus.
878  for (unsigned i=0; i<names.size(); ++i)
879  names_table.push_back_entry(names[i]);
880 
881  if (verbose)
882  {
883  libMesh::out << "Writing variable name(s) to file: " << std::endl;
884  for (unsigned i=0; i<names.size(); ++i)
885  libMesh::out << names_table.get_char_star(i) << std::endl;
886  }
887 
889  var_type,
890  names.size(),
891  names_table.get_char_star_star()
892  );
893 
894  EX_CHECK_ERR(ex_err, "Error writing variable names.");
895  }
896 }
897 
898 
899 
900 void ExodusII_IO_Helper::read_elemental_var_values(std::string elemental_var_name, int time_step)
901 {
902  // CAUTION: this assumes that libMesh element numbering is identical to exodus block-by-block element numbering
903  // There is no way how to get the whole elemental field from the exodus file, so we have to go block by block
904 
905  elem_var_values.resize(num_elem);
906 
907  this->read_var_names(ELEMENTAL);
908 
909  // See if we can find the variable we are looking for
910  unsigned int var_index = 0;
911  bool found = false;
912 
913  // Do a linear search for nodal_var_name in nodal_var_names
914  for (; var_index<elem_var_names.size(); ++var_index)
915  {
916  found = (elem_var_names[var_index] == elemental_var_name);
917  if (found)
918  break;
919  }
920 
921  if (!found)
922  {
923  libMesh::err << "Unable to locate variable named: " << elemental_var_name << std::endl;
924  libMesh::err << "Available variables: " << std::endl;
925  for (unsigned int i=0; i<elem_var_names.size(); ++i)
926  libMesh::err << elem_var_names[i] << std::endl;
927 
928  libmesh_error();
929  }
930 
931  unsigned int ex_el_num = 0;
932  for (unsigned int i=0; i<static_cast<unsigned int>(num_elem_blk); i++)
933  {
934  int n_blk_elems = 0;
936  block_ids[i],
937  NULL,
938  &n_blk_elems,
939  NULL,
940  NULL);
941  EX_CHECK_ERR(ex_err, "Error getting number of elements in block.");
942 
943  std::vector<Real> block_elem_var_values(num_elem);
945  time_step,
946  var_index+1,
947  block_ids[i],
948  n_blk_elems,
949  &block_elem_var_values[0]);
950  EX_CHECK_ERR(ex_err, "Error getting elemental values.");
951 
952  for (unsigned int j=0; j<static_cast<unsigned int>(n_blk_elems); j++)
953  {
954  elem_var_values[ex_el_num] = block_elem_var_values[j];
955  ex_el_num++;
956  }
957  }
958 }
959 
960 
961 // For Writing Solutions
962 
963 void ExodusII_IO_Helper::create(std::string filename)
964 {
965  // If we're processor 0, always create the file.
966  // If we running on all procs, e.g. as one of several Nemesis files, also
967  // call create there.
968  if ((this->processor_id() == 0) || (!_run_only_on_proc0))
969  {
970  // Fall back on double precision when necessary since ExodusII
971  // doesn't seem to support long double
972  int comp_ws = std::min(sizeof(Real), sizeof(double));
973  int io_ws = std::min(sizeof(Real), sizeof(double));
974 
975  ex_id = exII::ex_create(filename.c_str(), EX_CLOBBER, &comp_ws, &io_ws);
976 
977  EX_CHECK_ERR(ex_id, "Error creating ExodusII mesh file.");
978 
979  if (verbose)
980  libMesh::out << "File created successfully." << std::endl;
981  }
982 
983  opened_for_writing = true;
984  current_filename = filename;
985 }
986 
987 
988 
989 
990 void ExodusII_IO_Helper::initialize_discontinuous(std::string str_title, const MeshBase & mesh)
991 {
992  if ((_run_only_on_proc0) && (this->processor_id() != 0))
993  return;
994 
996  num_dim = mesh.mesh_dimension();
997  else
998  num_dim = mesh.spatial_dimension();
999 
1002  for (; it!=end; ++it)
1003  num_nodes += (*it)->n_nodes();
1004 
1005  num_elem = mesh.n_elem();
1006 
1007  std::vector<boundary_id_type> unique_side_boundaries;
1008  std::vector<boundary_id_type> unique_node_boundaries;
1009 
1010  mesh.boundary_info->build_side_boundary_ids(unique_side_boundaries);
1011  mesh.boundary_info->build_node_boundary_ids(unique_node_boundaries);
1012 
1013  num_side_sets = unique_side_boundaries.size();
1014  num_node_sets = unique_node_boundaries.size();
1015 
1016  //loop through element and map between block and element vector
1017  std::map<subdomain_id_type, std::vector<unsigned int> > subdomain_map;
1018 
1019  for (it=mesh.active_elements_begin(); it!=end; ++it)
1020  {
1021  const Elem * elem = *it;
1022  subdomain_id_type cur_subdomain = elem->subdomain_id();
1023 
1024  subdomain_map[cur_subdomain].push_back(elem->id());
1025  }
1026  num_elem_blk = subdomain_map.size();
1027 
1028  if (str_title.size() > MAX_LINE_LENGTH)
1029  {
1030  libMesh::err << "Warning, Exodus files cannot have titles longer than "
1031  << MAX_LINE_LENGTH
1032  << " characters. Your title will be truncated."
1033  << std::endl;
1034  str_title.resize(MAX_LINE_LENGTH);
1035  }
1036 
1038  str_title.c_str(),
1039  num_dim,
1040  num_nodes,
1041  num_elem,
1042  num_elem_blk,
1043  num_node_sets,
1044  num_side_sets);
1045 
1046  EX_CHECK_ERR(ex_err, "Error initializing new Exodus file.");
1047 }
1048 
1049 
1050 
1051 void ExodusII_IO_Helper::initialize(std::string str_title, const MeshBase & mesh)
1052 {
1053  // n_active_elem() is a parallel_only function
1054  unsigned int n_active_elem = mesh.n_active_elem();
1055 
1056  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1057  return;
1058 
1060  num_dim = mesh.mesh_dimension();
1061  else
1062  num_dim = mesh.spatial_dimension();
1063 
1064  num_nodes = mesh.n_nodes();
1065  num_elem = mesh.n_elem();
1066 
1067  std::vector<boundary_id_type> unique_side_boundaries;
1068  std::vector<boundary_id_type> unique_node_boundaries;
1069 
1070  mesh.boundary_info->build_side_boundary_ids(unique_side_boundaries);
1071  mesh.boundary_info->build_node_boundary_ids(unique_node_boundaries);
1072 
1073  num_side_sets = unique_side_boundaries.size();
1074  num_node_sets = unique_node_boundaries.size();
1075 
1076  //loop through element and map between block and element vector
1077  std::map<subdomain_id_type, std::vector<unsigned int> > subdomain_map;
1078 
1081  for (; it!=end; ++it)
1082  {
1083  const Elem * elem = *it;
1084  subdomain_id_type cur_subdomain = elem->subdomain_id();
1085 
1086  subdomain_map[cur_subdomain].push_back(elem->id());
1087  }
1088  num_elem_blk = subdomain_map.size();
1089 
1090  if (str_title.size() > MAX_LINE_LENGTH)
1091  {
1092  libMesh::err << "Warning, Exodus files cannot have titles longer than "
1093  << MAX_LINE_LENGTH
1094  << " characters. Your title will be truncated."
1095  << std::endl;
1096  str_title.resize(MAX_LINE_LENGTH);
1097  }
1098 
1100  str_title.c_str(),
1101  num_dim,
1102  num_nodes,
1103  n_active_elem,
1104  num_elem_blk,
1105  num_node_sets,
1106  num_side_sets);
1107 
1108  EX_CHECK_ERR(ex_err, "Error initializing new Exodus file.");
1109 }
1110 
1111 
1112 
1114 {
1115  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1116  return;
1117 
1118  // Make room in the coordinate vectors
1119  x.resize(num_nodes);
1120  y.resize(num_nodes);
1121  z.resize(num_nodes);
1122 
1123  // And in the node_num_map - since the nodes aren't organized in
1124  // blocks, libmesh will always write out the identity map
1125  // here... unless there has been some refinement and coarsening. If
1126  // the nodes aren't renumbered after refinement and coarsening,
1127  // there may be 'holes' in the numbering, so we write out the node
1128  // map just to be on the safe side.
1129  node_num_map.resize(num_nodes);
1130 
1131  {
1134  for (unsigned i = 0; it != end; ++it, ++i)
1135  {
1136  const Node* node = *it;
1137 
1138  x[i] = (*node)(0) + _coordinate_offset(0);
1139 
1140 #if LIBMESH_DIM > 1
1141  y[i]=(*node)(1) + _coordinate_offset(1);
1142 #else
1143  y[i]=0.;
1144 #endif
1145 #if LIBMESH_DIM > 2
1146  z[i]=(*node)(2) + _coordinate_offset(2);
1147 #else
1148  z[i]=0.;
1149 #endif
1150 
1151  // Fill in node_num_map entry with the proper (1-based) node id
1152  node_num_map[i] = node->id() + 1;
1153  }
1154  }
1155 
1157  x.empty() ? NULL : &x[0],
1158  y.empty() ? NULL : &y[0],
1159  z.empty() ? NULL : &z[0]);
1160 
1161  EX_CHECK_ERR(ex_err, "Error writing coordinates to Exodus file.");
1162 
1163  // Also write the (1-based) node_num_map to the file.
1165  EX_CHECK_ERR(ex_err, "Error writing node_num_map");
1166 }
1167 
1168 
1169 
1171 {
1172  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1173  return;
1174 
1175  x.resize(num_nodes);
1176  y.resize(num_nodes);
1177  z.resize(num_nodes);
1178 
1181 
1182  unsigned int i = 0;
1183  for (; it!=end; ++it)
1184  for (unsigned int n=0; n<(*it)->n_nodes(); n++)
1185  {
1186  x[i]=(*it)->point(n)(0);
1187 #if LIBMESH_DIM > 1
1188  y[i]=(*it)->point(n)(1);
1189 #else
1190  y[i]=0.;
1191 #endif
1192 #if LIBMESH_DIM > 2
1193  z[i]=(*it)->point(n)(2);
1194 #else
1195  z[i]=0.;
1196 #endif
1197  i++;
1198  }
1199 
1201  x.empty() ? NULL : &x[0],
1202  y.empty() ? NULL : &y[0],
1203  z.empty() ? NULL : &z[0]);
1204 
1205  EX_CHECK_ERR(ex_err, "Error writing coordinates to Exodus file.");
1206 }
1207 
1208 
1209 
1211 {
1212  // n_active_elem() is a parallel_only function
1213  unsigned int n_active_elem = mesh.n_active_elem();
1214 
1215  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1216  return;
1217 
1218  // Map from block ID to a vector of element IDs in that block. Element
1219  // IDs are now of type dof_id_type, subdomain IDs are of type subdomain_id_type.
1220  typedef std::map<subdomain_id_type, std::vector<dof_id_type> > subdomain_map_type;
1221  subdomain_map_type subdomain_map;
1222 
1225  //loop through element and map between block and element vector
1226  for (; mesh_it!=end; ++mesh_it)
1227  {
1228  const Elem * elem = *mesh_it;
1229  subdomain_map[ elem->subdomain_id() ].push_back(elem->id());
1230  }
1231 
1232  // element map vector
1233  num_elem_blk = subdomain_map.size();
1234  block_ids.resize(num_elem_blk);
1235  elem_num_map.resize(n_active_elem);
1236  std::vector<int>::iterator curr_elem_map_end = elem_num_map.begin();
1237 
1238  // Note: It appears that there is a bug in exodusII::ex_put_name where
1239  // the index returned from the ex_id_lkup is erronously used. For now
1240  // the work around is to use the alternative function ex_put_names, but
1241  // this function requires a char** datastructure.
1242  NamesData names_table(num_elem_blk, MAX_STR_LENGTH);
1243 
1244  // This counter is used to fill up the libmesh_elem_num_to_exodus map in the loop below.
1245  unsigned libmesh_elem_num_to_exodus_counter = 0;
1246 
1247  // counter indexes into the block_ids vector
1248  unsigned int counter = 0;
1249 
1250  for (subdomain_map_type::iterator it=subdomain_map.begin(); it!=subdomain_map.end(); ++it)
1251  {
1252  block_ids[counter] = (*it).first;
1253  names_table.push_back_entry(mesh.subdomain_name((*it).first));
1254 
1255  // Get a reference to a vector of element IDs for this subdomain.
1256  subdomain_map_type::mapped_type& tmp_vec = (*it).second;
1257 
1259 
1260  //Use the first element in this block to get representative information.
1261  //Note that Exodus assumes all elements in a block are of the same type!
1262  //We are using that same assumption here!
1263  const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(mesh.elem(tmp_vec[0])->type());
1264  num_nodes_per_elem = mesh.elem(tmp_vec[0])->n_nodes();
1265 
1267  (*it).first,
1268  conv.exodus_elem_type().c_str(),
1269  tmp_vec.size(),
1271  /*num_attr=*/0);
1272 
1273  EX_CHECK_ERR(ex_err, "Error writing element block.");
1274 
1275  connect.resize(tmp_vec.size()*num_nodes_per_elem);
1276 
1277  for (unsigned int i=0; i<tmp_vec.size(); i++)
1278  {
1279  unsigned int elem_id = tmp_vec[i];
1280  libmesh_elem_num_to_exodus[elem_id] = ++libmesh_elem_num_to_exodus_counter; // 1-based indexing for Exodus
1281 
1282  const Elem* elem = mesh.elem(elem_id);
1283 
1284  // We *might* be able to get away with writing mixed element
1285  // types which happen to have the same number of nodes, but
1286  // do we actually *want* to get away with that?
1287  // .) No visualization software would be able to handle it.
1288  // .) There'd be no way for us to read it back in reliably.
1289  // .) Even elements with the same number of nodes may have different connectivities (?)
1290 
1291  // This needs to be more than an assert so we don't fail
1292  // with a mysterious segfault while trying to write mixed
1293  // element meshes in optimized mode.
1294  if (elem->type() != conv.get_canonical_type())
1295  {
1296  libMesh::err << "Error: Exodus requires all elements with a given subdomain ID to be the same type.\n"
1297  << "Can't write both "
1298  << Utility::enum_to_string(elem->type())
1299  << " and "
1301  << " in the same block!"
1302  << std::endl;
1303  libmesh_error();
1304  }
1305 
1306  for (unsigned int j=0; j<static_cast<unsigned int>(num_nodes_per_elem); ++j)
1307  {
1308  unsigned connect_index = (i*num_nodes_per_elem)+j;
1309  unsigned elem_node_index = conv.get_inverse_node_map(j); // inverse node map is for writing.
1310  if (verbose)
1311  {
1312  libMesh::out << "Exodus node index: " << j
1313  << "=LibMesh node index " << elem_node_index << std::endl;
1314  }
1315 
1316  // FIXME: We are hard-coding the 1-based node numbering assumption here.
1317  connect[connect_index] = elem->node(elem_node_index)+1;
1318  }
1319  }
1320  ex_err = exII::ex_put_elem_conn(ex_id, (*it).first, &connect[0]);
1321  EX_CHECK_ERR(ex_err, "Error writing element connectivities");
1322 
1323  // This transform command stores its result in a range that begins at the third argument,
1324  // so this command is adding values to the elem_num_map vector starting from curr_elem_map_end.
1325  curr_elem_map_end = std::transform(tmp_vec.begin(),
1326  tmp_vec.end(),
1327  curr_elem_map_end,
1328  std::bind2nd(std::plus<subdomain_map_type::mapped_type::value_type>(), 1)); // Adds one to each id to make a 1-based exodus file!
1329 
1330  // But if we don't want to add one, we just want to put the values
1331  // of tmp_vec into elem_map in the right location, we can use
1332  // std::copy().
1333  // curr_elem_map_end = std::copy(tmp_vec.begin(), tmp_vec.end(), curr_elem_map_end);
1334 
1335  counter++;
1336  }
1337 
1338  // write out the element number map that we created
1340  EX_CHECK_ERR(ex_err, "Error writing element map");
1341 
1342  // Write out the block names
1343  if (num_elem_blk > 0)
1344  {
1346  EX_CHECK_ERR(ex_err, "Error writing element names");
1347  }
1348 }
1349 
1350 
1351 
1352 
1354 {
1355  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1356  return;
1357 
1358  typedef std::map<subdomain_id_type, std::vector<dof_id_type> > subdomain_map_type;
1359  subdomain_map_type subdomain_map;
1360 
1363  // loop through element and map between block and element vector
1364  for (; mesh_it!=end; ++mesh_it)
1365  {
1366  const Elem * elem = *mesh_it;
1367  subdomain_map[ elem->subdomain_id() ].push_back(elem->id());
1368  }
1369 
1370  // This counter is used to fill up the libmesh_elem_num_to_exodus map in the loop below.
1371  unsigned libmesh_elem_num_to_exodus_counter = 0;
1372 
1373  for (subdomain_map_type::iterator it=subdomain_map.begin(); it!=subdomain_map.end(); ++it)
1374  {
1375  subdomain_map_type::mapped_type& tmp_vec = (*it).second;
1376 
1378 
1379  //Use the first element in this block to get representative information.
1380  //Note that Exodus assumes all elements in a block are of the same type!
1381  //We are using that same assumption here!
1382  const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(mesh.elem(tmp_vec[0])->type());
1383  num_nodes_per_elem = mesh.elem(tmp_vec[0])->n_nodes();
1384 
1386  (*it).first,
1387  conv.exodus_elem_type().c_str(),
1388  tmp_vec.size(),
1390  /*num_attr=*/0);
1391 
1392  EX_CHECK_ERR(ex_err, "Error writing element block.");
1393 
1394  connect.resize(tmp_vec.size()*num_nodes_per_elem);
1395 
1396  for (unsigned int i=0; i<tmp_vec.size(); i++)
1397  {
1398  unsigned int elem_id = tmp_vec[i];
1399  libmesh_elem_num_to_exodus[elem_id] = ++libmesh_elem_num_to_exodus_counter; // 1-based indexing for Exodus
1400 
1401  for (unsigned int j=0; j<static_cast<unsigned int>(num_nodes_per_elem); j++)
1402  {
1403  const unsigned int connect_index = (i*num_nodes_per_elem)+j;
1404  const unsigned int elem_node_index = conv.get_inverse_node_map(j); // Inverse node map is for writing
1405  if (verbose)
1406  {
1407  libMesh::out << "Exodus node index: " << j
1408  << "=LibMesh node index " << elem_node_index << std::endl;
1409  }
1410  connect[connect_index] = i*num_nodes_per_elem+elem_node_index+1;
1411  }
1412  }
1413  ex_err = exII::ex_put_elem_conn(ex_id, (*it).first, &connect[0]);
1414  EX_CHECK_ERR(ex_err, "Error writing element connectivities");
1415 
1416  // Create space in elem_num_map
1417  elem_num_map.resize(tmp_vec.size());
1418 
1419  // copy the contents of tmp_vec into the elem_map vector
1420  std::copy(tmp_vec.begin(), tmp_vec.end(), elem_num_map.begin());
1421 
1422  // And write to file
1424  EX_CHECK_ERR(ex_err, "Error writing element map");
1425  }
1426 
1428  EX_CHECK_ERR(ex_err, "Error flushing buffers to file.");
1429 }
1430 
1431 
1432 
1434 {
1435  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1436  return;
1437 
1439 
1440  std::vector< dof_id_type > el;
1441  std::vector< unsigned short int > sl;
1442  std::vector< boundary_id_type > il;
1443 
1444  mesh.boundary_info->build_side_list(el, sl, il);
1445 
1446  // Maps from sideset id to the element and sides
1447  std::map<int, std::vector<int> > elem;
1448  std::map<int, std::vector<int> > side;
1449 
1450  // Accumulate the vectors to pass into ex_put_side_set
1451  for (unsigned int i=0; i<el.size(); i++)
1452  {
1453  std::vector<const Elem *> family;
1454 #ifdef LIBMESH_ENABLE_AMR
1455 
1459  mesh.elem(el[i])->active_family_tree_by_side(family, sl[i], false);
1460 #else
1461  family.push_back(mesh.elem(el[i]));
1462 #endif
1463 
1464  for (unsigned int j=0; j<family.size(); ++j)
1465  {
1466  const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(mesh.elem(family[j]->id())->type());
1467 
1468  // Use the libmesh to exodus datastructure map to get the proper sideset IDs
1469  // The datastructure contains the "collapsed" contiguous ids
1470  elem[il[i]].push_back(libmesh_elem_num_to_exodus[family[j]->id()]);
1471  side[il[i]].push_back(conv.get_inverse_side_map(sl[i]));
1472  }
1473  }
1474 
1475  std::vector<boundary_id_type> side_boundary_ids;
1476  mesh.boundary_info->build_side_boundary_ids(side_boundary_ids);
1477 
1478  // Write out the sideset names, but only if there is something to write
1479  if (side_boundary_ids.size() > 0)
1480  {
1481  NamesData names_table(side_boundary_ids.size(), MAX_STR_LENGTH);
1482 
1483  for (unsigned int i=0; i<side_boundary_ids.size(); i++)
1484  {
1485  int ss_id = side_boundary_ids[i];
1486 
1487  int actual_id = ss_id;
1488 
1489  names_table.push_back_entry(mesh.boundary_info->sideset_name(ss_id));
1490 
1491  ex_err = exII::ex_put_side_set_param(ex_id, actual_id, elem[ss_id].size(), 0);
1492  EX_CHECK_ERR(ex_err, "Error writing sideset parameters");
1493 
1494  ex_err = exII::ex_put_side_set(ex_id, actual_id, &elem[ss_id][0], &side[ss_id][0]);
1495  EX_CHECK_ERR(ex_err, "Error writing sidesets");
1496  }
1497 
1498  ex_err = exII::ex_put_names(ex_id, exII::EX_SIDE_SET, names_table.get_char_star_star());
1499  EX_CHECK_ERR(ex_err, "Error writing sideset names");
1500  }
1501 }
1502 
1503 
1504 
1506 {
1507  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1508  return;
1509 
1510  std::vector< dof_id_type > nl;
1511  std::vector< boundary_id_type > il;
1512 
1513  mesh.boundary_info->build_node_list(nl, il);
1514 
1515  // Maps from nodeset id to the nodes
1516  std::map<boundary_id_type, std::vector<int> > node;
1517 
1518  // Accumulate the vectors to pass into ex_put_node_set
1519  for (unsigned int i=0; i<nl.size(); i++)
1520  node[il[i]].push_back(nl[i]+1);
1521 
1522  std::vector<boundary_id_type> node_boundary_ids;
1523  mesh.boundary_info->build_node_boundary_ids(node_boundary_ids);
1524 
1525  // Write out the nodeset names, but only if there is something to write
1526  if (node_boundary_ids.size() > 0)
1527  {
1528  NamesData names_table(node_boundary_ids.size(), MAX_STR_LENGTH);
1529 
1530  for (unsigned int i=0; i<node_boundary_ids.size(); i++)
1531  {
1532  int nodeset_id = node_boundary_ids[i];
1533 
1534  int actual_id = nodeset_id;
1535 
1536  names_table.push_back_entry(mesh.boundary_info->nodeset_name(nodeset_id));
1537 
1538  ex_err = exII::ex_put_node_set_param(ex_id, actual_id, node[nodeset_id].size(), 0);
1539  EX_CHECK_ERR(ex_err, "Error writing nodeset parameters");
1540 
1541  ex_err = exII::ex_put_node_set(ex_id, actual_id, &node[nodeset_id][0]);
1542  EX_CHECK_ERR(ex_err, "Error writing nodesets");
1543  }
1544 
1545  // Write out the nodeset names
1546  ex_err = exII::ex_put_names(ex_id, exII::EX_NODE_SET, names_table.get_char_star_star());
1547  EX_CHECK_ERR(ex_err, "Error writing nodeset names");
1548  }
1549 }
1550 
1551 
1552 
1553 void ExodusII_IO_Helper::initialize_element_variables(std::vector<std::string> names)
1554 {
1555  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1556  return;
1557 
1558  // Quick return if there are no element variables to write
1559  if (names.size() == 0)
1560  return;
1561 
1562  // Quick return if we have already called this function
1564  return;
1565 
1566  // Be sure that variables in the file match what we are asking for
1567  if (num_elem_vars > 0)
1568  {
1569  this->check_existing_vars(ELEMENTAL, names, this->elem_var_names);
1570  return;
1571  }
1572 
1573  // Set the flag so we can skip this stuff on subsequent calls to
1574  // initialize_element_variables()
1575  _elem_vars_initialized = true;
1576 
1577  this->write_var_names(ELEMENTAL, names);
1578 
1579  // Form the element variable truth table and send to Exodus.
1580  // This tells which variables are written to which blocks,
1581  // and can dramatically speed up writing element variables
1582  //
1583  // We really should initialize all entries in the truth table to 0
1584  // and then loop over all subdomains, setting their entries to 1
1585  // if a given variable exists on that subdomain. However,
1586  // we don't have that information, and the element variables
1587  // passed to us are padded with zeroes for the blocks where
1588  // they aren't defined. To be consistent with that, fill
1589  // the truth table with ones.
1590  std::vector<int> truth_tab(num_elem_blk*num_elem_vars, 1);
1592  num_elem_blk,
1593  num_elem_vars,
1594  &truth_tab[0]);
1595  EX_CHECK_ERR(ex_err, "Error writing element truth table.");
1596 }
1597 
1598 
1599 
1600 void ExodusII_IO_Helper::initialize_nodal_variables(std::vector<std::string> names)
1601 {
1602  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1603  return;
1604 
1605  // Quick return if there are no nodal variables to write
1606  if (names.size() == 0)
1607  return;
1608 
1609  // Quick return if we have already called this function
1611  return;
1612 
1613  // Be sure that variables in the file match what we are asking for
1614  if (num_nodal_vars > 0)
1615  {
1616  this->check_existing_vars(NODAL, names, this->nodal_var_names);
1617  return;
1618  }
1619 
1620  // Set the flag so we can skip the rest of this function on subsequent calls.
1621  _nodal_vars_initialized = true;
1622 
1623  this->write_var_names(NODAL, names);
1624 }
1625 
1626 
1627 
1628 void ExodusII_IO_Helper::initialize_global_variables(std::vector<std::string> names)
1629 {
1630  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1631  return;
1632 
1633  // Quick return if there are no global variables to write
1634  if (names.size() == 0)
1635  return;
1636 
1638  return;
1639 
1640  // Be sure that variables in the file match what we are asking for
1641  if (num_global_vars > 0)
1642  {
1643  this->check_existing_vars(GLOBAL, names, this->global_var_names);
1644  return;
1645  }
1646 
1647  _global_vars_initialized = true;
1648 
1649  this->write_var_names(GLOBAL, names);
1650 }
1651 
1652 
1653 
1655  std::vector<std::string>& names,
1656  std::vector<std::string>& names_from_file)
1657 {
1658  // There may already be global variables in the file (for example,
1659  // if we're appending) and in that case, we
1660  // 1.) Cannot initialize them again.
1661  // 2.) Should check to be sure that the global variable names are the same.
1662 
1663  // Fills up names_from_file for us
1664  this->read_var_names(type);
1665 
1666  // Both the names of the global variables and their order must match
1667  if (names_from_file != names)
1668  {
1669  libMesh::err << "Error! The Exodus file already contains the variables:" << std::endl;
1670  for (unsigned i=0; i<names_from_file.size(); ++i)
1671  libMesh::out << names_from_file[i] << std::endl;
1672 
1673  libMesh::err << "And you asked to write:" << std::endl;
1674  for (unsigned i=0; i<names.size(); ++i)
1675  libMesh::out << names[i] << std::endl;
1676 
1677  libmesh_error();
1678  }
1679 }
1680 
1681 
1682 
1684 {
1685  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1686  return;
1687 
1688  ex_err = exII::ex_put_time(ex_id, timestep, &time);
1689  EX_CHECK_ERR(ex_err, "Error writing timestep.");
1690 
1692  EX_CHECK_ERR(ex_err, "Error flushing buffers to file.");
1693 }
1694 
1695 
1696 
1697 void ExodusII_IO_Helper::write_element_values(const MeshBase & mesh, const std::vector<Number> & values, int timestep)
1698 {
1699  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1700  return;
1701 
1702  // Loop over the element blocks and write the data one block at a time
1703  std::map<unsigned int, std::vector<unsigned int> > subdomain_map;
1704 
1705  const unsigned int num_vars = values.size() / num_elem;
1706 
1709 
1710  // loop through element and map between block and element vector
1711  for (; mesh_it!=end; ++mesh_it)
1712  {
1713  const Elem * elem = *mesh_it;
1714  subdomain_map[elem->subdomain_id()].push_back(elem->id());
1715  }
1716 
1717  // For each variable, create a 'data' array which holds all the elemental variable
1718  // values *for a given block* on this processor, then write that data vector to file
1719  // before moving onto the next block.
1720  for (unsigned int i=0; i<num_vars; ++i)
1721  {
1722  // The size of the subdomain map is the number of blocks.
1723  std::map<unsigned int, std::vector<unsigned int> >::iterator it = subdomain_map.begin();
1724 
1725  for (unsigned int j=0; it!=subdomain_map.end(); ++it, ++j)
1726  {
1727  const std::vector<unsigned int> & elem_nums = (*it).second;
1728  const unsigned int num_elems_this_block = elem_nums.size();
1729  std::vector<Number> data(num_elems_this_block);
1730 
1731  for (unsigned int k=0; k<num_elems_this_block; ++k)
1732  data[k] = values[i*num_elem + elem_nums[k]];
1733 
1735  timestep,
1736  i+1,
1737  this->get_block_id(j),
1738  num_elems_this_block,
1739  &data[0]);
1740  EX_CHECK_ERR(ex_err, "Error writing element values.");
1741  }
1742  }
1743 
1745  EX_CHECK_ERR(ex_err, "Error flushing buffers to file.");
1746 }
1747 
1748 
1749 
1750 void ExodusII_IO_Helper::write_nodal_values(int var_id, const std::vector<Number> & values, int timestep)
1751 {
1752  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1753  return;
1754 
1755  ex_err = exII::ex_put_nodal_var(ex_id, timestep, var_id, num_nodes, &values[0]);
1756  EX_CHECK_ERR(ex_err, "Error writing nodal values.");
1757 
1759  EX_CHECK_ERR(ex_err, "Error flushing buffers to file.");
1760 }
1761 
1762 
1763 
1764 void ExodusII_IO_Helper::write_information_records(const std::vector<std::string>& records)
1765 {
1766  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1767  return;
1768 
1769  // There may already be information records in the file (for
1770  // example, if we're appending) and in that case, according to the
1771  // Exodus documentation, writing more information records is not
1772  // supported.
1773  int num_info = inquire(exII::EX_INQ_INFO, "Error retrieving the number of information records from file!");
1774  if (num_info > 0)
1775  {
1776  libMesh::err << "Warning! The Exodus file already contains information records.\n"
1777  << "Exodus does not support writing additional records in this situation."
1778  << std::endl;
1779  return;
1780  }
1781 
1782  int num_records = records.size();
1783 
1784  if (num_records > 0)
1785  {
1786  NamesData info(num_records, MAX_LINE_LENGTH);
1787 
1788  // If an entry is longer than MAX_LINE_LENGTH characters it's not an error, we just
1789  // write the first MAX_LINE_LENGTH characters to the file.
1790  for (unsigned i=0; i<records.size(); ++i)
1791  info.push_back_entry(records[i]);
1792 
1793  ex_err = exII::ex_put_info(ex_id, num_records, info.get_char_star_star());
1794  EX_CHECK_ERR(ex_err, "Error writing global values.");
1795 
1797  EX_CHECK_ERR(ex_err, "Error flushing buffers to file.");
1798  }
1799 }
1800 
1801 
1802 
1803 void ExodusII_IO_Helper::write_global_values(const std::vector<Number> & values, int timestep)
1804 {
1805  if ((_run_only_on_proc0) && (this->processor_id() != 0))
1806  return;
1807 
1808  ex_err = exII::ex_put_glob_vars(ex_id, timestep, num_global_vars, &values[0]);
1809  EX_CHECK_ERR(ex_err, "Error writing global values.");
1810 
1812  EX_CHECK_ERR(ex_err, "Error flushing buffers to file.");
1813 }
1814 
1815 
1816 
1818 {
1820 }
1821 
1823 {
1824  _coordinate_offset = p;
1825 }
1826 
1827 
1828 
1829 // ------------------------------------------------------------
1830 // ExodusII_IO_Helper::Conversion class members
1832 {
1833  init_element_equivalence_map();
1834 
1835  // Do only upper-case comparisons
1836  std::transform(type_str.begin(), type_str.end(), type_str.begin(), ::toupper);
1837 
1838  std::map<std::string, libMeshEnums::ElemType>::iterator it =
1839  element_equivalence_map.find(type_str);
1840 
1841  if (it != element_equivalence_map.end())
1842  return assign_conversion( it->second );
1843  else
1844  {
1845  libMesh::err << "ERROR! Unrecognized element type_str: " << type_str << std::endl;
1846  libmesh_error();
1847  }
1848 
1849  libmesh_error();
1850 
1851  // dummy return value, we won't get here
1852  return assign_conversion (EDGE2);
1853 }
1854 
1855 
1856 
1858 {
1859  switch (type)
1860  {
1861  case EDGE2:
1862  {
1863  const Conversion conv(edge2_node_map,
1864  ARRAY_LENGTH(edge2_node_map),
1865  edge2_node_map, // inverse node map same as forward node map
1866  ARRAY_LENGTH(edge2_node_map),
1867  edge_edge_map,
1868  ARRAY_LENGTH(edge_edge_map),
1869  edge_inverse_edge_map,
1870  ARRAY_LENGTH(edge_inverse_edge_map),
1871  EDGE2, "EDGE2");
1872  return conv;
1873  }
1874  case EDGE3:
1875  {
1876  const Conversion conv(edge3_node_map,
1877  ARRAY_LENGTH(edge3_node_map),
1878  edge3_node_map, // inverse node map same as forward node map
1879  ARRAY_LENGTH(edge3_node_map),
1880  edge_edge_map,
1881  ARRAY_LENGTH(edge_edge_map),
1882  edge_inverse_edge_map,
1883  ARRAY_LENGTH(edge_inverse_edge_map),
1884  EDGE3, "EDGE3");
1885  return conv;
1886  }
1887  case QUAD4:
1888  {
1889  const Conversion conv(quad4_node_map,
1890  ARRAY_LENGTH(quad4_node_map),
1891  quad4_node_map, // inverse node map same as forward node map
1892  ARRAY_LENGTH(quad4_node_map),
1893  quad_edge_map,
1894  ARRAY_LENGTH(quad_edge_map),
1895  quad_inverse_edge_map,
1896  ARRAY_LENGTH(quad_inverse_edge_map),
1897  QUAD4,
1898  "QUAD4");
1899  return conv;
1900  }
1901 
1902  case QUAD8:
1903  {
1904  const Conversion conv(quad8_node_map,
1905  ARRAY_LENGTH(quad8_node_map),
1906  quad8_node_map, // inverse node map same as forward node map
1907  ARRAY_LENGTH(quad8_node_map),
1908  quad_edge_map,
1909  ARRAY_LENGTH(quad_edge_map),
1910  quad_inverse_edge_map,
1911  ARRAY_LENGTH(quad_inverse_edge_map),
1912  QUAD8,
1913  "QUAD8");
1914  return conv;
1915  }
1916 
1917  case QUAD9:
1918  {
1919  const Conversion conv(quad9_node_map,
1920  ARRAY_LENGTH(quad9_node_map),
1921  quad9_node_map, // inverse node map same as forward node map
1922  ARRAY_LENGTH(quad9_node_map),
1923  quad_edge_map,
1924  ARRAY_LENGTH(quad_edge_map),
1925  quad_inverse_edge_map,
1926  ARRAY_LENGTH(quad_inverse_edge_map),
1927  QUAD9,
1928  "QUAD9");
1929  return conv;
1930  }
1931 
1932  case TRI3:
1933  {
1934  const Conversion conv(tri3_node_map,
1935  ARRAY_LENGTH(tri3_node_map),
1936  tri3_node_map, // inverse node map same as forward node map
1937  ARRAY_LENGTH(tri3_node_map),
1938  tri_edge_map,
1939  ARRAY_LENGTH(tri_edge_map),
1940  tri_inverse_edge_map,
1941  ARRAY_LENGTH(tri_inverse_edge_map),
1942  TRI3,
1943  "TRI3");
1944  return conv;
1945  }
1946 
1947  case TRI6:
1948  {
1949  const Conversion conv(tri6_node_map,
1950  ARRAY_LENGTH(tri6_node_map),
1951  tri6_node_map, // inverse node map same as forward node map
1952  ARRAY_LENGTH(tri6_node_map),
1953  tri_edge_map,
1954  ARRAY_LENGTH(tri_edge_map),
1955  tri_inverse_edge_map,
1956  ARRAY_LENGTH(tri_inverse_edge_map),
1957  TRI6,
1958  "TRI6");
1959  return conv;
1960  }
1961 
1962  case HEX8:
1963  {
1964  const Conversion conv(hex8_node_map,
1965  ARRAY_LENGTH(hex8_node_map),
1966  hex8_node_map, // inverse node map same as forward node map
1967  ARRAY_LENGTH(hex8_node_map),
1968  hex_face_map,
1969  ARRAY_LENGTH(hex_face_map),
1970  hex_inverse_face_map,
1971  ARRAY_LENGTH(hex_inverse_face_map),
1972  HEX8,
1973  "HEX8");
1974  return conv;
1975  }
1976 
1977  case HEX20:
1978  {
1979  const Conversion conv(hex20_node_map,
1980  ARRAY_LENGTH(hex20_node_map),
1981  hex20_node_map, // inverse node map same as forward node map
1982  ARRAY_LENGTH(hex20_node_map),
1983  hex_face_map,
1984  ARRAY_LENGTH(hex_face_map),
1985  hex_inverse_face_map,
1986  ARRAY_LENGTH(hex_inverse_face_map),
1987  HEX20,
1988  "HEX20");
1989  return conv;
1990  }
1991 
1992  case HEX27:
1993  {
1994  const Conversion conv(hex27_node_map,
1995  ARRAY_LENGTH(hex27_node_map),
1996  hex27_inverse_node_map, // different inverse node map for Hex27!
1997  ARRAY_LENGTH(hex27_inverse_node_map),
1998  hex27_face_map,
1999  ARRAY_LENGTH(hex27_face_map),
2000  hex27_inverse_face_map,
2001  ARRAY_LENGTH(hex27_inverse_face_map),
2002  HEX27,
2003  "HEX27");
2004  return conv;
2005  }
2006 
2007  case TET4:
2008  {
2009  const Conversion conv(tet4_node_map,
2010  ARRAY_LENGTH(tet4_node_map),
2011  tet4_node_map, // inverse node map same as forward node map
2012  ARRAY_LENGTH(tet4_node_map),
2013  tet_face_map,
2014  ARRAY_LENGTH(tet_face_map),
2015  tet_inverse_face_map,
2016  ARRAY_LENGTH(tet_inverse_face_map),
2017  TET4,
2018  "TETRA4");
2019  return conv;
2020  }
2021 
2022  case TET10:
2023  {
2024  const Conversion conv(tet10_node_map,
2025  ARRAY_LENGTH(tet10_node_map),
2026  tet10_node_map, // inverse node map same as forward node map
2027  ARRAY_LENGTH(tet10_node_map),
2028  tet_face_map,
2029  ARRAY_LENGTH(tet_face_map),
2030  tet_inverse_face_map,
2031  ARRAY_LENGTH(tet_inverse_face_map),
2032  TET10,
2033  "TETRA10");
2034  return conv;
2035  }
2036 
2037  case PRISM6:
2038  {
2039  const Conversion conv(prism6_node_map,
2040  ARRAY_LENGTH(prism6_node_map),
2041  prism6_node_map, // inverse node map same as forward node map
2042  ARRAY_LENGTH(prism6_node_map),
2043  prism_face_map,
2044  ARRAY_LENGTH(prism_face_map),
2045  prism_inverse_face_map,
2046  ARRAY_LENGTH(prism_inverse_face_map),
2047  PRISM6,
2048  "WEDGE");
2049  return conv;
2050  }
2051 
2052  case PRISM15:
2053  {
2054  const Conversion conv(prism15_node_map,
2055  ARRAY_LENGTH(prism15_node_map),
2056  prism15_node_map, // inverse node map same as forward node map
2057  ARRAY_LENGTH(prism15_node_map),
2058  prism_face_map,
2059  ARRAY_LENGTH(prism_face_map),
2060  prism_inverse_face_map,
2061  ARRAY_LENGTH(prism_inverse_face_map),
2062  PRISM15,
2063  "WEDGE15");
2064  return conv;
2065  }
2066 
2067  case PRISM18:
2068  {
2069  const Conversion conv(prism18_node_map,
2070  ARRAY_LENGTH(prism18_node_map),
2071  prism18_node_map, // inverse node map same as forward node map
2072  ARRAY_LENGTH(prism18_node_map),
2073  prism_face_map,
2074  ARRAY_LENGTH(prism_face_map),
2075  prism_inverse_face_map,
2076  ARRAY_LENGTH(prism_inverse_face_map),
2077  PRISM18,
2078  "WEDGE18");
2079  return conv;
2080  }
2081 
2082  case PYRAMID5:
2083  {
2084  const Conversion conv(pyramid5_node_map,
2085  ARRAY_LENGTH(pyramid5_node_map),
2086  pyramid5_node_map, // inverse node map same as forward node map
2087  ARRAY_LENGTH(pyramid5_node_map),
2088  pyramid_face_map,
2089  ARRAY_LENGTH(pyramid_face_map),
2090  pyramid_inverse_face_map,
2091  ARRAY_LENGTH(pyramid_inverse_face_map),
2092  PYRAMID5,
2093  "PYRAMID5");
2094  return conv;
2095  }
2096 
2097  case PYRAMID14:
2098  {
2099  const Conversion conv(pyramid14_node_map,
2100  ARRAY_LENGTH(pyramid14_node_map),
2101  pyramid14_node_map, // inverse node map same as forward node map
2102  ARRAY_LENGTH(pyramid14_node_map),
2103  pyramid_face_map,
2104  ARRAY_LENGTH(pyramid_face_map),
2105  pyramid_inverse_face_map,
2106  ARRAY_LENGTH(pyramid_inverse_face_map),
2107  PYRAMID14,
2108  "PYRAMID14");
2109  return conv;
2110  }
2111 
2112  default:
2113  libmesh_error();
2114  }
2115 
2116  libmesh_error();
2117 
2118  // dummy return value, we will never get here
2119  const Conversion conv(tri3_node_map,
2120  ARRAY_LENGTH(tri3_node_map),
2121  tri3_node_map, // inverse node map same as forward node map
2122  ARRAY_LENGTH(tri3_node_map),
2123  tri_edge_map,
2124  ARRAY_LENGTH(tri_edge_map),
2125  tri_inverse_edge_map,
2126  ARRAY_LENGTH(tri_inverse_edge_map),
2127  TRI3,
2128  "TRI3");
2129  return conv;
2130 }
2131 
2132 
2133 
2134 ExodusII_IO_Helper::NamesData::NamesData(size_t n_strings, size_t string_length) :
2135  data_table(n_strings),
2136  data_table_pointers(n_strings),
2137  counter(0),
2138  table_size(n_strings)
2139 {
2140  for (size_t i=0; i<n_strings; ++i)
2141  {
2142  data_table[i].resize(string_length + 1);
2143 
2144  // NULL-terminate these strings, just to be safe.
2145  data_table[i][0] = '\0';
2146 
2147  // Set pointer into the data_table
2148  data_table_pointers[i] = &(data_table[i][0]);
2149  }
2150 }
2151 
2152 
2153 
2155 {
2156  libmesh_assert_less (counter, table_size);
2157 
2158  // 1.) Copy the C++ string into the vector<char>...
2159  size_t num_copied = name.copy(&data_table[counter][0], data_table[counter].size()-1);
2160 
2161  // 2.) ...And null-terminate it.
2162  data_table[counter][num_copied] = '\0';
2163 
2164  // Go to next row
2165  ++counter;
2166 }
2167 
2168 
2169 
2171 {
2172  return &data_table_pointers[0];
2173 }
2174 
2175 
2176 
2178 {
2179  if (static_cast<unsigned>(i) >= table_size)
2180  {
2181  libMesh::err << "Requested char* " << i << " but only have " << table_size << "!" << std::endl;
2182  libmesh_error();
2183  }
2184  else
2185  return &(data_table[i][0]);
2186 }
2187 
2188 
2189 } // namespace libMesh
2190 
2191 
2192 
2193 #endif // #ifdef LIBMESH_HAVE_EXODUS_API

Site Created By: libMesh Developers
Last modified: February 07 2014 16:57:04 UTC

Hosted By:
SourceForge.net Logo