Loading [MathJax]/extensions/tex2jax.js
libMesh
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
gmv_io.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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 // C++ includes
19 #include <iomanip>
20 #include <fstream>
21 #include <vector>
22 #include <cctype> // isspace
23 
24 // Local includes
25 #include "libmesh/libmesh_config.h"
26 #include "libmesh/libmesh_logging.h"
27 #include "libmesh/gmv_io.h"
28 #include "libmesh/mesh_base.h"
29 #include "libmesh/elem.h"
30 #include "libmesh/equation_systems.h"
31 #include "libmesh/numeric_vector.h"
32 #include "libmesh/enum_to_string.h"
33 #include "libmesh/enum_io_package.h"
34 #include "libmesh/enum_elem_type.h"
35 #include "libmesh/int_range.h"
36 #include "libmesh/utility.h"
37 
38 // Wrap everything in a GMVLib namespace and
39 // use extern "C" to avoid name mangling.
40 #ifdef LIBMESH_HAVE_GMV
41 namespace GMVLib
42 {
43 extern "C"
44 {
45 #include "gmvread.h"
46 }
47 }
48 #endif
49 
50 // anonymous namespace to hold local data
51 namespace
52 {
53 using namespace libMesh;
54 
63 struct ElementDefinition {
64  // GMV element name
65  std::string label;
66 
67  // Used to map libmesh nodes to GMV for writing
68  std::vector<unsigned> node_map;
69 };
70 
71 
72 // maps from a libMesh element type to the proper GMV
73 // ElementDefinition. Placing the data structure here in this
74 // anonymous namespace gives us the benefits of a global variable
75 // without the nasty side-effects.
76 std::map<ElemType, ElementDefinition> eletypes;
77 
78 // Helper function to fill up eletypes map
79 void add_eletype_entry(ElemType libmesh_elem_type,
80  const unsigned * node_map,
81  const std::string & gmv_label,
82  unsigned nodes_size )
83 {
84  // If map entry does not exist, this will create it
85  ElementDefinition & map_entry = eletypes[libmesh_elem_type];
86 
87  // Set the label
88  map_entry.label = gmv_label;
89 
90  // Use the "swap trick" from Scott Meyer's "Effective STL" to swap
91  // an unnamed temporary vector into the map_entry's vector. Note:
92  // the vector(iter, iter) constructor is used.
93  std::vector<unsigned int>(node_map,
94  node_map+nodes_size).swap(map_entry.node_map);
95 }
96 
97 
98 // ------------------------------------------------------------
99 // helper function to initialize the eletypes map
100 void init_eletypes ()
101 {
102  if (eletypes.empty())
103  {
104  // This should happen only once. The first time this method
105  // is called the eletypes data structure will be empty, and
106  // we will fill it. Any subsequent calls will find an initialized
107  // eletypes map and will do nothing.
108 
109  // EDGE2
110  {
111  const unsigned int node_map[] = {0,1};
112  add_eletype_entry(EDGE2, node_map, "line 2", 2);
113  }
114 
115  // LINE3
116  {
117  const unsigned int node_map[] = {0,1,2};
118  add_eletype_entry(EDGE3, node_map, "3line 3", 3);
119  }
120 
121  // TRI3
122  {
123  const unsigned int node_map[] = {0,1,2};
124  add_eletype_entry(TRI3, node_map, "tri3 3", 3);
125  }
126 
127  // TRI6
128  {
129  const unsigned int node_map[] = {0,1,2,3,4,5};
130  add_eletype_entry(TRI6, node_map, "6tri 6", 6);
131  }
132 
133  // QUAD4
134  {
135  const unsigned int node_map[] = {0,1,2,3};
136  add_eletype_entry(QUAD4, node_map, "quad 4", 4);
137  }
138 
139  // QUAD8, QUAD9
140  {
141  const unsigned int node_map[] = {0,1,2,3,4,5,6,7};
142  add_eletype_entry(QUAD8, node_map, "8quad 8", 8);
143 
144  // QUAD9 was not supported by GMV but it gets the same entry, even the label (is that correct?)
145  eletypes[QUAD9] = eletypes[QUAD8];
146  }
147 
148  // HEX8
149  {
150  const unsigned int node_map[] = {0,1,2,3,4,5,6,7};
151  add_eletype_entry(HEX8, node_map, "phex8 8", 8);
152  }
153 
154  // HEX20, HEX27
155  {
156  // Note: This map is its own inverse
157  const unsigned int node_map[] = {0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19,12,13,14,15};
158  add_eletype_entry(HEX20, node_map, "phex20 20", 20);
159 
160  // HEX27 was not supported by GMV but it gets the same entry, even the label (is that correct?)
161  eletypes[HEX27] = eletypes[HEX20];
162  }
163 
164  // TET4
165  {
166  // This is correct, see write_ascii_old_impl() to confirm.
167  // This map is also its own inverse.
168  const unsigned node_map[] = {0,2,1,3};
169  add_eletype_entry(TET4, node_map, "tet 4", 4);
170  }
171 
172  // TET10
173  {
174  const unsigned int node_map[] = {0,1,2,3,4,5,6,7,8,9};
175  add_eletype_entry(TET10, node_map, "ptet10 10", 10);
176  }
177 
178  // PRISM6
179  {
180  const unsigned int node_map[] = {0,1,2,3,4,5};
181  add_eletype_entry(PRISM6, node_map, "pprism6 6", 6);
182  }
183 
184  // PRISM15, PRISM18
185  {
186  // Note: This map is its own inverse
187  const unsigned int node_map[] = {0,1,2,3,4,5,6,7,8,12,13,14, 9,10,11};
188  add_eletype_entry(PRISM15, node_map, "pprism15 15", 15);
189 
190  // PRISM18 was not supported by GMV but it gets the same entry, even the label (is that correct?)
191  eletypes[PRISM18] = eletypes[PRISM15];
192  }
193  //==============================
194  }
195 }
196 
197 } // end anonymous namespace
198 
199 
200 namespace libMesh
201 {
202 
203 // Initialize the static data members by calling the static build functions.
204 std::map<std::string, ElemType> GMVIO::_reading_element_map = GMVIO::build_reading_element_map();
205 
206 
207 
208 // Static function used to build the _reading_element_map.
209 std::map<std::string, ElemType> GMVIO::build_reading_element_map()
210 {
211  std::map<std::string, ElemType> ret;
212 
213  ret["line"] = EDGE2;
214  ret["tri"] = TRI3;
215  ret["tri3"] = TRI3;
216  ret["quad"] = QUAD4;
217  ret["tet"] = TET4;
218  ret["ptet4"] = TET4;
219  ret["hex"] = HEX8;
220  ret["phex8"] = HEX8;
221  ret["prism"] = PRISM6;
222  ret["pprism6"] = PRISM6;
223  ret["phex20"] = HEX20;
224  ret["phex27"] = HEX27;
225  ret["pprism15"] = PRISM15;
226  ret["ptet10"] = TET10;
227  ret["6tri"] = TRI6;
228  ret["8quad"] = QUAD8;
229  ret["3line"] = EDGE3;
230 
231  // Unsupported/Unused types
232  // ret["vface2d"]
233  // ret["vface3d"]
234  // ret["pyramid"]
235  // ret["ppyrmd5"]
236  // ret["ppyrmd13"]
237 
238  return ret;
239 }
240 
241 
244  _binary (false),
245  _discontinuous (false),
246  _partitioning (true),
247  _write_subdomain_id_as_material (false),
248  _subdivide_second_order (true),
249  _p_levels (true),
250  _next_elem_id (0)
251 {
252 }
253 
254 
255 
259  _binary (false),
260  _discontinuous (false),
261  _partitioning (true),
262  _write_subdomain_id_as_material (false),
263  _subdivide_second_order (true),
264  _p_levels (true),
265  _next_elem_id (0)
266 {
267 }
268 
269 
270 
271 void GMVIO::write (const std::string & fname)
272 {
273  if (this->binary())
274  this->write_binary (fname);
275  else
276  this->write_ascii_old_impl (fname);
277 }
278 
279 
280 
281 void GMVIO::write_nodal_data (const std::string & fname,
282  const std::vector<Number> & soln,
283  const std::vector<std::string> & names)
284 {
285  LOG_SCOPE("write_nodal_data()", "GMVIO");
286 
287  if (this->binary())
288  this->write_binary (fname, &soln, &names);
289  else
290  this->write_ascii_old_impl (fname, &soln, &names);
291 }
292 
293 
294 
295 void GMVIO::write_ascii_new_impl (const std::string & fname,
296  const std::vector<Number> * v,
297  const std::vector<std::string> * solution_names)
298 {
299 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
300 
301  libMesh::err << "WARNING: GMVIO::write_ascii_new_impl() not infinite-element aware!"
302  << std::endl;
303  libmesh_here();
304 
305  // Set it to our current precision
306  this->write_ascii_old_impl (fname, v, solution_names);
307 
308 #else
309 
310  // Get a reference to the mesh
312 
313  // This is a parallel_only function
314  const unsigned int n_active_elem = mesh.n_active_elem();
315 
316  if (MeshOutput<MeshBase>::mesh().processor_id() != 0)
317  return;
318 
319  // Open the output file stream
320  std::ofstream out_stream (fname.c_str());
321 
322  out_stream << std::setprecision(this->ascii_precision());
323 
324  // Make sure it opened correctly
325  if (!out_stream.good())
326  libmesh_file_error(fname.c_str());
327 
328  unsigned int mesh_max_p_level = 0;
329 
330  // Begin interfacing with the GMV data file
331  {
332  out_stream << "gmvinput ascii\n\n";
333 
334  // write the nodes
335  out_stream << "nodes " << mesh.n_nodes() << "\n";
336  for (auto n : make_range(mesh.n_nodes()))
337  out_stream << mesh.point(n)(0) << " ";
338  out_stream << "\n";
339 
340  for (auto n : make_range(mesh.n_nodes()))
341 #if LIBMESH_DIM > 1
342  out_stream << mesh.point(n)(1) << " ";
343 #else
344  out_stream << 0. << " ";
345 #endif
346  out_stream << "\n";
347 
348  for (auto n : make_range(mesh.n_nodes()))
349 #if LIBMESH_DIM > 2
350  out_stream << mesh.point(n)(2) << " ";
351 #else
352  out_stream << 0. << " ";
353 #endif
354  out_stream << "\n\n";
355  }
356 
357  {
358  // write the connectivity
359  out_stream << "cells " << n_active_elem << "\n";
360 
361  // initialize the eletypes map (eletypes is a file-global variable)
362  init_eletypes();
363 
364  for (const auto & elem : mesh.active_element_ptr_range())
365  {
366  mesh_max_p_level = std::max(mesh_max_p_level,
367  elem->p_level());
368 
369  // Make sure we have a valid entry for
370  // the current element type.
371  libmesh_assert (eletypes.count(elem->type()));
372 
373  const ElementDefinition & ele = eletypes[elem->type()];
374 
375  // The element mapper better not require any more nodes
376  // than are present in the current element!
377  libmesh_assert_less_equal (ele.node_map.size(), elem->n_nodes());
378 
379  out_stream << ele.label << "\n";
380  for (auto i : index_range(ele.node_map))
381  out_stream << elem->node_id(ele.node_map[i])+1 << " ";
382  out_stream << "\n";
383  }
384  out_stream << "\n";
385  }
386 
387  // optionally write the partition information
388  if (this->partitioning())
389  {
390  libmesh_error_msg_if(this->write_subdomain_id_as_material(),
391  "Not yet supported in GMVIO::write_ascii_new_impl");
392 
393  out_stream << "material "
394  << mesh.n_partitions()
395  // Note: GMV may give you errors like
396  // Error, material for cell 1 is greater than 1
397  // Error, material for cell 2 is greater than 1
398  // Error, material for cell 3 is greater than 1
399  // ... because you put the wrong number of partitions here.
400  // To ensure you write the correct number of materials, call
401  // mesh.recalculate_n_partitions() before writing out the
402  // mesh.
403  // Note: we can't call it now because the Mesh is const here and
404  // it is a non-const function.
405  << " 0\n";
406 
407  for (auto proc : make_range(mesh.n_partitions()))
408  out_stream << "proc_" << proc << "\n";
409 
410  // FIXME - don't we need to use an ElementDefinition here? - RHS
411  for (const auto & elem : mesh.active_element_ptr_range())
412  out_stream << elem->processor_id()+1 << "\n";
413  out_stream << "\n";
414  }
415 
416  // If there are *any* variables at all in the system (including
417  // p level, or arbitrary cell-based data)
418  // to write, the gmv file needs to contain the word "variable"
419  // on a line by itself.
420  bool write_variable = false;
421 
422  // 1.) p-levels
423  if (this->p_levels() && mesh_max_p_level)
424  write_variable = true;
425 
426  // 2.) solution data
427  if ((solution_names != nullptr) && (v != nullptr))
428  write_variable = true;
429 
430  // 3.) cell-centered data
431  if (!(this->_cell_centered_data.empty()))
432  write_variable = true;
433 
434  if (write_variable)
435  out_stream << "variable\n";
436 
437  // if ((this->p_levels() && mesh_max_p_level) ||
438  // ((solution_names != nullptr) && (v != nullptr)))
439  // out_stream << "variable\n";
440 
441  // optionally write the polynomial degree information
442  if (this->p_levels() && mesh_max_p_level)
443  {
444  out_stream << "p_level 0\n";
445 
446  for (const auto & elem : mesh.active_element_ptr_range())
447  {
448  const ElementDefinition & ele = eletypes[elem->type()];
449 
450  // The element mapper better not require any more nodes
451  // than are present in the current element!
452  libmesh_assert_less_equal (ele.node_map.size(), elem->n_nodes());
453 
454  for (std::size_t i=0, enms=ele.node_map.size(); i < enms; i++)
455  out_stream << elem->p_level() << " ";
456  }
457  out_stream << "\n\n";
458  }
459 
460 
461  // optionally write cell-centered data
462  if (!(this->_cell_centered_data.empty()))
463  {
464  for (const auto & [var_name, the_array] : this->_cell_centered_data)
465  {
466  // write out the variable name, followed by a zero.
467  out_stream << var_name << " 0\n";
468 
469  // Loop over active elements, write out cell data. If second-order cells
470  // are split into sub-elements, the sub-elements inherit their parent's
471  // cell-centered data.
472  for (const auto & elem : mesh.active_element_ptr_range())
473  {
474  // Use the element's ID to find the value.
475  libmesh_assert_less (elem->id(), the_array->size());
476  const Real the_value = (*the_array)[elem->id()];
477 
478  if (this->subdivide_second_order())
479  for (unsigned int se=0, nse=elem->n_sub_elem(); se<nse; se++)
480  out_stream << the_value << " ";
481  else
482  out_stream << the_value << " ";
483  }
484 
485  out_stream << "\n\n";
486  }
487  }
488 
489 
490  // optionally write the data
491  if ((solution_names != nullptr) && (v != nullptr))
492  {
493  const unsigned int n_vars = solution_names->size();
494 
495  if (!(v->size() == mesh.n_nodes()*n_vars))
496  libMesh::err << "ERROR: v->size()=" << v->size()
497  << ", mesh.n_nodes()=" << mesh.n_nodes()
498  << ", n_vars=" << n_vars
499  << ", mesh.n_nodes()*n_vars=" << mesh.n_nodes()*n_vars
500  << "\n";
501 
502  libmesh_assert_equal_to (v->size(), mesh.n_nodes()*n_vars);
503 
504  for (unsigned int c=0; c<n_vars; c++)
505  {
506 
507 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
508 
509  // in case of complex data, write _three_ data sets
510  // for each component
511 
512  // this is the real part
513  out_stream << "r_" << (*solution_names)[c] << " 1\n";
514 
515  for (auto n : make_range(mesh.n_nodes()))
516  out_stream << (*v)[n*n_vars + c].real() << " ";
517 
518  out_stream << "\n\n";
519 
520  // this is the imaginary part
521  out_stream << "i_" << (*solution_names)[c] << " 1\n";
522 
523  for (auto n : make_range(mesh.n_nodes()))
524  out_stream << (*v)[n*n_vars + c].imag() << " ";
525 
526  out_stream << "\n\n";
527 
528  // this is the magnitude
529  out_stream << "a_" << (*solution_names)[c] << " 1\n";
530  for (auto n : make_range(mesh.n_nodes()))
531  out_stream << std::abs((*v)[n*n_vars + c]) << " ";
532 
533  out_stream << "\n\n";
534 
535 #else
536 
537  out_stream << (*solution_names)[c] << " 1\n";
538 
539  for (auto n : make_range(mesh.n_nodes()))
540  out_stream << (*v)[n*n_vars + c] << " ";
541 
542  out_stream << "\n\n";
543 
544 #endif
545  }
546 
547  }
548 
549  // If we wrote any variables, we have to close the variable section now
550  if (write_variable)
551  out_stream << "endvars\n";
552 
553 
554  // end of the file
555  out_stream << "\nendgmv\n";
556 
557 #endif
558 }
559 
560 
561 
562 
563 
564 
565 void GMVIO::write_ascii_old_impl (const std::string & fname,
566  const std::vector<Number> * v,
567  const std::vector<std::string> * solution_names)
568 {
569  // Get a reference to the mesh
571 
572  // Use a MeshSerializer object to gather a parallel mesh before outputting it.
573  // Note that we cast away constness here (which is bad), but the destructor of
574  // the MeshSerializer object reparallelizes the Mesh, hopefully keeping it
575  // "logically const" outside the context of this function...
576  MeshSerializer serialize(const_cast<MeshBase &>(mesh),
578 
579  // These are parallel_only functions
580  const dof_id_type n_active_elem = mesh.n_active_elem(),
581  n_active_sub_elem = mesh.n_active_sub_elem();
582 
583  if (MeshOutput<MeshBase>::mesh().processor_id() != 0)
584  return;
585 
586  // Open the output file stream
587  std::ofstream out_stream (fname.c_str());
588 
589  // Set it to our current precision
590  out_stream << std::setprecision(this->ascii_precision());
591 
592  // Make sure it opened correctly
593  if (!out_stream.good())
594  libmesh_file_error(fname.c_str());
595 
596  // Make sure our nodes are contiguous and serialized
597  libmesh_assert_equal_to (mesh.n_nodes(), mesh.max_node_id());
598 
599  // libmesh_assert (mesh.is_serial());
600  // if (!mesh.is_serial())
601  // {
602  // if (MeshOutput<MeshBase>::mesh().processor_id() == 0)
603  // libMesh::err << "Error: GMVIO cannot yet write a DistributedMesh solution"
604  // << std::endl;
605  // return;
606  // }
607 
608  unsigned int mesh_max_p_level = 0;
609 
610  // Begin interfacing with the GMV data file
611 
612  // FIXME - if subdivide_second_order() is off,
613  // we probably should only be writing the
614  // vertex nodes - RHS
615  {
616  // write the nodes
617 
618  out_stream << "gmvinput ascii\n\n";
619  out_stream << "nodes " << mesh.n_nodes() << '\n';
620  for (auto n : make_range(mesh.n_nodes()))
621  out_stream << mesh.point(n)(0) << " ";
622 
623  out_stream << '\n';
624 
625  for (auto n : make_range(mesh.n_nodes()))
626 #if LIBMESH_DIM > 1
627  out_stream << mesh.point(n)(1) << " ";
628 #else
629  out_stream << 0. << " ";
630 #endif
631 
632  out_stream << '\n';
633 
634  for (auto n : make_range(mesh.n_nodes()))
635 #if LIBMESH_DIM > 2
636  out_stream << mesh.point(n)(2) << " ";
637 #else
638  out_stream << 0. << " ";
639 #endif
640 
641  out_stream << '\n' << '\n';
642  }
643 
644 
645 
646  {
647  // write the connectivity
648 
649  out_stream << "cells ";
650  if (this->subdivide_second_order())
651  out_stream << n_active_sub_elem;
652  else
653  out_stream << n_active_elem;
654  out_stream << '\n';
655 
656  // The same temporary storage will be used for each element
657  std::vector<dof_id_type> conn;
658 
659  for (const auto & elem : mesh.active_element_ptr_range())
660  {
661  mesh_max_p_level = std::max(mesh_max_p_level,
662  elem->p_level());
663 
664  switch (elem->dim())
665  {
666  case 1:
667  {
668  if (this->subdivide_second_order())
669  for (auto se : make_range(elem->n_sub_elem()))
670  {
671  out_stream << "line 2\n";
672  elem->connectivity(se, TECPLOT, conn);
673  for (const auto & idx : conn)
674  out_stream << idx << " ";
675 
676  out_stream << '\n';
677  }
678  else
679  {
680  out_stream << "line 2\n";
681  if (elem->default_order() == FIRST)
682  elem->connectivity(0, TECPLOT, conn);
683  else
684  {
685  std::unique_ptr<Elem> lo_elem = Elem::build(Elem::first_order_equivalent_type(elem->type()));
686  for (auto i : lo_elem->node_index_range())
687  lo_elem->set_node(i, const_cast<Node*>(elem->node_ptr(i)));
688  lo_elem->connectivity(0, TECPLOT, conn);
689  }
690  for (const auto & idx : conn)
691  out_stream << idx << " ";
692 
693  out_stream << '\n';
694  }
695 
696  break;
697  }
698 
699  case 2:
700  {
701  if (this->subdivide_second_order())
702  for (auto se : make_range(elem->n_sub_elem()))
703  {
704  // Quad elements
705  if ((elem->type() == QUAD4) ||
706  (elem->type() == QUAD8) || // Note: QUAD8 will be output as one central quad and
707  // four surrounding triangles (though they will be written
708  // to GMV as QUAD4s).
709  (elem->type() == QUAD9)
710 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
711  || (elem->type() == INFQUAD4)
712  || (elem->type() == INFQUAD6)
713 #endif
714  )
715  {
716  out_stream << "quad 4\n";
717  elem->connectivity(se, TECPLOT, conn);
718  for (const auto & idx : conn)
719  out_stream << idx << " ";
720  }
721 
722  // Triangle elements
723  else if ((elem->type() == TRI3) ||
724  (elem->type() == TRI6))
725  {
726  out_stream << "tri 3\n";
727  elem->connectivity(se, TECPLOT, conn);
728  for (unsigned int i=0; i<3; i++)
729  out_stream << conn[i] << " ";
730  }
731  else
732  libmesh_error_msg("Unsupported element type: " << Utility::enum_to_string(elem->type()));
733  }
734  else // !this->subdivide_second_order()
735  {
736  // Quad elements
737  if ((elem->type() == QUAD4)
738 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
739  || (elem->type() == INFQUAD4)
740 #endif
741  )
742  {
743  elem->connectivity(0, TECPLOT, conn);
744  out_stream << "quad 4\n";
745  for (const auto & idx : conn)
746  out_stream << idx << " ";
747  }
748  else if ((elem->type() == QUAD8) ||
749  (elem->type() == QUAD9)
750 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
751  || (elem->type() == INFQUAD6)
752 #endif
753  )
754  {
755  std::unique_ptr<Elem> lo_elem = Elem::build(Elem::first_order_equivalent_type(elem->type()));
756  for (auto i : lo_elem->node_index_range())
757  lo_elem->set_node(i, const_cast<Node*>(elem->node_ptr(i)));
758  lo_elem->connectivity(0, TECPLOT, conn);
759  out_stream << "quad 4\n";
760  for (const auto & idx : conn)
761  out_stream << idx << " ";
762  }
763  else if (elem->type() == TRI3)
764  {
765  elem->connectivity(0, TECPLOT, conn);
766  out_stream << "tri 3\n";
767  for (unsigned int i=0; i<3; i++)
768  out_stream << conn[i] << " ";
769  }
770  else if (elem->type() == TRI6)
771  {
772  std::unique_ptr<Elem> lo_elem = Elem::build(Elem::first_order_equivalent_type(elem->type()));
773  for (auto i : lo_elem->node_index_range())
774  lo_elem->set_node(i, const_cast<Node*>(elem->node_ptr(i)));
775  lo_elem->connectivity(0, TECPLOT, conn);
776  out_stream << "tri 3\n";
777  for (unsigned int i=0; i<3; i++)
778  out_stream << conn[i] << " ";
779  }
780 
781  out_stream << '\n';
782  }
783 
784  break;
785  }
786 
787  case 3:
788  {
789  if (this->subdivide_second_order())
790  for (auto se : make_range(elem->n_sub_elem()))
791  {
792 
793 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
794  if ((elem->type() == HEX8) ||
795  (elem->type() == HEX27))
796  {
797  out_stream << "phex8 8\n";
798  elem->connectivity(se, TECPLOT, conn);
799  for (const auto & idx : conn)
800  out_stream << idx << " ";
801  }
802 
803  else if (elem->type() == HEX20)
804  {
805  out_stream << "phex20 20\n";
806  out_stream << elem->node_id(0)+1 << " "
807  << elem->node_id(1)+1 << " "
808  << elem->node_id(2)+1 << " "
809  << elem->node_id(3)+1 << " "
810  << elem->node_id(4)+1 << " "
811  << elem->node_id(5)+1 << " "
812  << elem->node_id(6)+1 << " "
813  << elem->node_id(7)+1 << " "
814  << elem->node_id(8)+1 << " "
815  << elem->node_id(9)+1 << " "
816  << elem->node_id(10)+1 << " "
817  << elem->node_id(11)+1 << " "
818  << elem->node_id(16)+1 << " "
819  << elem->node_id(17)+1 << " "
820  << elem->node_id(18)+1 << " "
821  << elem->node_id(19)+1 << " "
822  << elem->node_id(12)+1 << " "
823  << elem->node_id(13)+1 << " "
824  << elem->node_id(14)+1 << " "
825  << elem->node_id(15)+1 << " ";
826  }
827 
828  // According to our copy of gmvread.c, this is the
829  // mapping for the Hex27 element. Unfortunately,
830  // I tried it and Paraview does not seem to be
831  // able to read Hex27 elements. Since this is
832  // unlikely to change any time soon, we'll
833  // continue to write out Hex27 elements as 8 Hex8
834  // sub-elements.
835  //
836  // TODO:
837  // 1.) If we really wanted to use this code for
838  // something, we'd want to avoid repeating the
839  // hard-coded node ordering from the HEX20 case.
840  // These should both be able to use
841  // ElementDefinitions.
842  // 2.) You would also need to change
843  // Hex27::n_sub_elem() to return 1, not sure how
844  // much other code that would affect...
845 
846  // else if (elem->type() == HEX27)
847  // {
848  // out_stream << "phex27 27\n";
849  // out_stream << elem->node_id(0)+1 << " "
850  // << elem->node_id(1)+1 << " "
851  // << elem->node_id(2)+1 << " "
852  // << elem->node_id(3)+1 << " "
853  // << elem->node_id(4)+1 << " "
854  // << elem->node_id(5)+1 << " "
855  // << elem->node_id(6)+1 << " "
856  // << elem->node_id(7)+1 << " "
857  // << elem->node_id(8)+1 << " "
858  // << elem->node_id(9)+1 << " "
859  // << elem->node_id(10)+1 << " "
860  // << elem->node_id(11)+1 << " "
861  // << elem->node_id(16)+1 << " "
862  // << elem->node_id(17)+1 << " "
863  // << elem->node_id(18)+1 << " "
864  // << elem->node_id(19)+1 << " "
865  // << elem->node_id(12)+1 << " "
866  // << elem->node_id(13)+1 << " "
867  // << elem->node_id(14)+1 << " "
868  // << elem->node_id(15)+1 << " "
869  // // mid-face nodes
870  // << elem->node_id(21)+1 << " " // GMV front
871  // << elem->node_id(22)+1 << " " // GMV right
872  // << elem->node_id(23)+1 << " " // GMV back
873  // << elem->node_id(24)+1 << " " // GMV left
874  // << elem->node_id(20)+1 << " " // GMV bottom
875  // << elem->node_id(25)+1 << " " // GMV top
876  // // center node
877  // << elem->node_id(26)+1 << " ";
878  // }
879 
880 #else // LIBMESH_ENABLE_INFINITE_ELEMENTS
881 
882  // In case of infinite elements, HEX20
883  // should be handled just like the
884  // INFHEX16, since these connect to each other
885  if ((elem->type() == HEX8) ||
886  (elem->type() == HEX27) ||
887  (elem->type() == INFHEX8) ||
888  (elem->type() == INFHEX16) ||
889  (elem->type() == INFHEX18) ||
890  (elem->type() == HEX20))
891  {
892  out_stream << "phex8 8\n";
893  elem->connectivity(se, TECPLOT, conn);
894  for (const auto & idx : conn)
895  out_stream << idx << " ";
896  }
897 #endif
898 
899  else if ((elem->type() == TET4) ||
900  (elem->type() == TET10))
901  {
902  out_stream << "tet 4\n";
903  // Tecplot connectivity returns 8 entries for
904  // the Tet, enough to store it as a degenerate Hex.
905  // For GMV we only pick out the four relevant node
906  // indices.
907  elem->connectivity(se, TECPLOT, conn);
908  out_stream << conn[0] << " " // libmesh tet node 0
909  << conn[2] << " " // libmesh tet node 2
910  << conn[1] << " " // libmesh tet node 1
911  << conn[4] << " "; // libmesh tet node 3
912  }
913 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
914  else if ((elem->type() == PRISM6) ||
915  (elem->type() == PRISM15) ||
916  (elem->type() == PRISM18) ||
917  (elem->type() == PYRAMID5))
918 #else
919  else if ((elem->type() == PRISM6) ||
920  (elem->type() == PRISM15) ||
921  (elem->type() == PRISM18) ||
922  (elem->type() == PYRAMID5) ||
923  (elem->type() == INFPRISM6) ||
924  (elem->type() == INFPRISM12))
925 #endif
926  {
927  // Note that the prisms are treated as
928  // degenerated phex8's.
929  out_stream << "phex8 8\n";
930  elem->connectivity(se, TECPLOT, conn);
931  for (const auto & idx : conn)
932  out_stream << idx << " ";
933  }
934 
935  else
936  libmesh_error_msg("Encountered an unrecognized element " \
937  << "type: " << elem->type() \
938  << "\nPossibly a dim-1 dimensional " \
939  << "element? Aborting...");
940 
941  out_stream << '\n';
942  }
943  else // !this->subdivide_second_order()
944  {
945  std::unique_ptr<Elem> lo_elem = Elem::build(Elem::first_order_equivalent_type(elem->type()));
946  for (auto i : lo_elem->node_index_range())
947  lo_elem->set_node(i, const_cast<Node*>(elem->node_ptr(i)));
948  if ((lo_elem->type() == HEX8)
949 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
950  || (lo_elem->type() == HEX27)
951 #endif
952  )
953  {
954  out_stream << "phex8 8\n";
955  lo_elem->connectivity(0, TECPLOT, conn);
956  for (const auto & idx : conn)
957  out_stream << idx << " ";
958  }
959 
960  else if (lo_elem->type() == TET4)
961  {
962  out_stream << "tet 4\n";
963  lo_elem->connectivity(0, TECPLOT, conn);
964  out_stream << conn[0] << " "
965  << conn[2] << " "
966  << conn[1] << " "
967  << conn[4] << " ";
968  }
969  else if ((lo_elem->type() == PRISM6)
970 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
971  || (lo_elem->type() == INFPRISM6)
972 #endif
973  )
974  {
975  // Note that the prisms are treated as
976  // degenerated phex8's.
977  out_stream << "phex8 8\n";
978  lo_elem->connectivity(0, TECPLOT, conn);
979  for (const auto & idx : conn)
980  out_stream << idx << " ";
981  }
982 
983  else
984  libmesh_error_msg("Encountered an unrecognized element " \
985  << "type. Possibly a dim-1 dimensional " \
986  << "element? Aborting...");
987 
988  out_stream << '\n';
989  }
990 
991  break;
992  }
993 
994  default:
995  libmesh_error_msg("Unsupported element dimension: " <<
996  elem->dim());
997  }
998  }
999 
1000  out_stream << '\n';
1001  }
1002 
1003 
1004 
1005  // optionally write the partition information
1006  if (this->partitioning())
1007  {
1008  if (this->write_subdomain_id_as_material())
1009  {
1010  // Subdomain IDs can be non-contiguous and need not
1011  // necessarily start at 0. Furthermore, since the user is
1012  // free to define subdomain_id_type to be a signed type, we
1013  // can't even assume max(subdomain_id) >= # unique subdomain ids.
1014 
1015  // We build a map<subdomain_id, unsigned> to associate to each
1016  // user-selected subdomain ID a unique, contiguous unsigned value
1017  // which we can write to file.
1018  std::map<subdomain_id_type, unsigned> sbdid_map;
1019 
1020  // Try to insert with dummy value
1021  for (const auto & elem : mesh.active_element_ptr_range())
1022  sbdid_map.emplace(elem->subdomain_id(), 0);
1023 
1024  // Map is created, iterate through it to set indices. They will be
1025  // used repeatedly below.
1026  {
1027  unsigned ctr=0;
1028  for (auto & pr : sbdid_map)
1029  pr.second = ctr++;
1030  }
1031 
1032  out_stream << "material "
1033  << sbdid_map.size()
1034  << " 0\n";
1035 
1036  for (auto sbdid : make_range(sbdid_map.size()))
1037  out_stream << "proc_" << sbdid << "\n";
1038 
1039  for (const auto & elem : mesh.active_element_ptr_range())
1040  {
1041  // Find the unique index for elem->subdomain_id(), print that to file
1042  unsigned gmv_mat_number = libmesh_map_find(sbdid_map, elem->subdomain_id());
1043 
1044  if (this->subdivide_second_order())
1045  for (unsigned int se=0, nse=elem->n_sub_elem(); se<nse; se++)
1046  out_stream << gmv_mat_number+1 << '\n';
1047  else
1048  out_stream << gmv_mat_number+1 << "\n";
1049  }
1050  out_stream << '\n';
1051 
1052  }
1053  else // write processor IDs as materials. This is the default
1054  {
1055  out_stream << "material "
1056  << mesh.n_partitions()
1057  << " 0"<< '\n';
1058 
1059  for (auto proc : make_range(mesh.n_partitions()))
1060  out_stream << "proc_" << proc << '\n';
1061 
1062  for (const auto & elem : mesh.active_element_ptr_range())
1063  if (this->subdivide_second_order())
1064  for (unsigned int se=0, nse=elem->n_sub_elem(); se<nse; se++)
1065  out_stream << elem->processor_id()+1 << '\n';
1066  else
1067  out_stream << elem->processor_id()+1 << '\n';
1068 
1069  out_stream << '\n';
1070  }
1071  }
1072 
1073 
1074  // If there are *any* variables at all in the system (including
1075  // p level, or arbitrary cell-based data)
1076  // to write, the gmv file needs to contain the word "variable"
1077  // on a line by itself.
1078  bool write_variable = false;
1079 
1080  // 1.) p-levels
1081  if (this->p_levels() && mesh_max_p_level)
1082  write_variable = true;
1083 
1084  // 2.) solution data
1085  if ((solution_names != nullptr) && (v != nullptr))
1086  write_variable = true;
1087 
1088  // 3.) cell-centered data
1089  if (!(this->_cell_centered_data.empty()))
1090  write_variable = true;
1091 
1092  if (write_variable)
1093  out_stream << "variable\n";
1094 
1095 
1096  // optionally write the p-level information
1097  if (this->p_levels() && mesh_max_p_level)
1098  {
1099  out_stream << "p_level 0\n";
1100 
1101  for (const auto & elem : mesh.active_element_ptr_range())
1102  if (this->subdivide_second_order())
1103  for (unsigned int se=0, nse=elem->n_sub_elem(); se<nse; se++)
1104  out_stream << elem->p_level() << " ";
1105  else
1106  out_stream << elem->p_level() << " ";
1107  out_stream << "\n\n";
1108  }
1109 
1110 
1111 
1112 
1113  // optionally write cell-centered data
1114  if (!(this->_cell_centered_data.empty()))
1115  {
1116  for (const auto & [var_name, the_array] : this->_cell_centered_data)
1117  {
1118  // write out the variable name, followed by a zero.
1119  out_stream << var_name << " 0\n";
1120 
1121  // Loop over active elements, write out cell data. If second-order cells
1122  // are split into sub-elements, the sub-elements inherit their parent's
1123  // cell-centered data.
1124  for (const auto & elem : mesh.active_element_ptr_range())
1125  {
1126  // Use the element's ID to find the value...
1127  libmesh_assert_less (elem->id(), the_array->size());
1128  const Real the_value = (*the_array)[elem->id()];
1129 
1130  if (this->subdivide_second_order())
1131  for (unsigned int se=0, nse=elem->n_sub_elem(); se<nse; se++)
1132  out_stream << the_value << " ";
1133  else
1134  out_stream << the_value << " ";
1135  }
1136 
1137  out_stream << "\n\n";
1138  }
1139  }
1140 
1141 
1142 
1143 
1144  // optionally write the data
1145  if ((solution_names != nullptr) &&
1146  (v != nullptr))
1147  {
1148  const unsigned int n_vars =
1149  cast_int<unsigned int>(solution_names->size());
1150 
1151  if (!(v->size() == mesh.n_nodes()*n_vars))
1152  libMesh::err << "ERROR: v->size()=" << v->size()
1153  << ", mesh.n_nodes()=" << mesh.n_nodes()
1154  << ", n_vars=" << n_vars
1155  << ", mesh.n_nodes()*n_vars=" << mesh.n_nodes()*n_vars
1156  << std::endl;
1157 
1158  libmesh_assert_equal_to (v->size(), mesh.n_nodes()*n_vars);
1159 
1160  for (unsigned int c=0; c<n_vars; c++)
1161  {
1162 
1163 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1164 
1165  // in case of complex data, write _tree_ data sets
1166  // for each component
1167 
1168  // this is the real part
1169  out_stream << "r_" << (*solution_names)[c] << " 1\n";
1170 
1171  for (auto n : make_range(mesh.n_nodes()))
1172  out_stream << (*v)[n*n_vars + c].real() << " ";
1173 
1174  out_stream << '\n' << '\n';
1175 
1176 
1177  // this is the imaginary part
1178  out_stream << "i_" << (*solution_names)[c] << " 1\n";
1179 
1180  for (auto n : make_range(mesh.n_nodes()))
1181  out_stream << (*v)[n*n_vars + c].imag() << " ";
1182 
1183  out_stream << '\n' << '\n';
1184 
1185  // this is the magnitude
1186  out_stream << "a_" << (*solution_names)[c] << " 1\n";
1187  for (auto n : make_range(mesh.n_nodes()))
1188  out_stream << std::abs((*v)[n*n_vars + c]) << " ";
1189 
1190  out_stream << '\n' << '\n';
1191 
1192 #else
1193 
1194  out_stream << (*solution_names)[c] << " 1\n";
1195 
1196  for (auto n : make_range(mesh.n_nodes()))
1197  out_stream << (*v)[n*n_vars + c] << " ";
1198 
1199  out_stream << '\n' << '\n';
1200 
1201 #endif
1202  }
1203 
1204  }
1205 
1206  // If we wrote any variables, we have to close the variable section now
1207  if (write_variable)
1208  out_stream << "endvars\n";
1209 
1210 
1211  // end of the file
1212  out_stream << "\nendgmv\n";
1213 }
1214 
1215 
1216 
1217 
1218 
1219 
1220 
1221 void GMVIO::write_binary (const std::string & fname,
1222  const std::vector<Number> * vec,
1223  const std::vector<std::string> * solution_names)
1224 {
1225  // We use the file-scope global variable eletypes for mapping nodes
1226  // from GMV to libmesh indices, so initialize that data now.
1227  init_eletypes();
1228 
1229  // Get a reference to the mesh
1231 
1232  // This is a parallel_only function
1233  const dof_id_type n_active_elem = mesh.n_active_elem();
1234 
1235  if (MeshOutput<MeshBase>::mesh().processor_id() != 0)
1236  return;
1237 
1238  std::ofstream out_stream (fname.c_str());
1239 
1240  libmesh_assert (out_stream.good());
1241 
1242  unsigned int mesh_max_p_level = 0;
1243 
1244  std::string buffer;
1245 
1246  // Begin interfacing with the GMV data file
1247  {
1248  // write the nodes
1249  buffer = "gmvinput";
1250  out_stream.write(buffer.c_str(), buffer.size());
1251 
1252  buffer = "ieeei4r4";
1253  out_stream.write(buffer.c_str(), buffer.size());
1254  }
1255 
1256 
1257 
1258  // write the nodes
1259  {
1260  buffer = "nodes ";
1261  out_stream.write(buffer.c_str(), buffer.size());
1262 
1263  unsigned int tempint = mesh.n_nodes();
1264  out_stream.write(reinterpret_cast<char *>(&tempint), sizeof(unsigned int));
1265 
1266  // write the x coordinate
1267  std::vector<float> temp(mesh.n_nodes());
1268  for (auto v : make_range(mesh.n_nodes()))
1269  temp[v] = static_cast<float>(mesh.point(v)(0));
1270  out_stream.write(reinterpret_cast<char *>(temp.data()), sizeof(float)*mesh.n_nodes());
1271 
1272  // write the y coordinate
1273  for (auto v : make_range(mesh.n_nodes()))
1274  {
1275 #if LIBMESH_DIM > 1
1276  temp[v] = static_cast<float>(mesh.point(v)(1));
1277 #else
1278  temp[v] = 0.;
1279 #endif
1280  }
1281  out_stream.write(reinterpret_cast<char *>(temp.data()), sizeof(float)*mesh.n_nodes());
1282 
1283  // write the z coordinate
1284  for (auto v : make_range(mesh.n_nodes()))
1285  {
1286 #if LIBMESH_DIM > 2
1287  temp[v] = static_cast<float>(mesh.point(v)(2));
1288 #else
1289  temp[v] = 0.;
1290 #endif
1291  }
1292  out_stream.write(reinterpret_cast<char *>(temp.data()), sizeof(float)*mesh.n_nodes());
1293  }
1294 
1295 
1296  // write the connectivity
1297  {
1298  buffer = "cells ";
1299  out_stream.write(buffer.c_str(), buffer.size());
1300 
1301  unsigned int tempint = n_active_elem;
1302  out_stream.write(reinterpret_cast<char *>(&tempint), sizeof(unsigned int));
1303 
1304  for (const auto & elem : mesh.active_element_ptr_range())
1305  {
1306  mesh_max_p_level = std::max(mesh_max_p_level,
1307  elem->p_level());
1308 
1309  // The ElementDefinition label contains the GMV name
1310  // and the number of nodes for the respective
1311  // element.
1312  const ElementDefinition & ed = eletypes[elem->type()];
1313 
1314  // The ElementDefinition labels all have a name followed by a
1315  // whitespace and then the number of nodes. To write the
1316  // string in binary, we want to drop everything after that
1317  // space, and then pad the string out to 8 characters.
1318  buffer = ed.label;
1319 
1320  // Erase everything from the first whitespace character to the end of the string.
1321  buffer.erase(buffer.find_first_of(' '), std::string::npos);
1322 
1323  // Append whitespaces until the string is exactly 8 characters long.
1324  while (buffer.size() < 8)
1325  buffer.insert(buffer.end(), ' ');
1326 
1327  // Finally, write the 8 character stream to file.
1328  out_stream.write(buffer.c_str(), buffer.size());
1329 
1330  // Write the number of nodes that this type of element has.
1331  // Note: don't want to use the number of nodes of the element,
1332  // because certain elements, like QUAD9 and HEX27 only support
1333  // being written out as lower-order elements (QUAD8 and HEX20,
1334  // respectively).
1335  tempint = cast_int<unsigned int>(ed.node_map.size());
1336  out_stream.write(reinterpret_cast<char *>(&tempint), sizeof(unsigned int));
1337 
1338  // Write the element connectivity
1339  for (const auto & ed_id : ed.node_map)
1340  {
1341  dof_id_type id = elem->node_id(ed_id) + 1;
1342  out_stream.write(reinterpret_cast<char *>(&id), sizeof(dof_id_type));
1343  }
1344  }
1345  }
1346 
1347 
1348 
1349  // optionally write the partition information
1350  if (this->partitioning())
1351  {
1352  libmesh_error_msg_if(this->write_subdomain_id_as_material(),
1353  "Not yet supported in GMVIO::write_binary");
1354 
1355  buffer = "material";
1356  out_stream.write(buffer.c_str(), buffer.size());
1357 
1358  unsigned int tmpint = mesh.n_processors();
1359  out_stream.write(reinterpret_cast<char *>(&tmpint), sizeof(unsigned int));
1360 
1361  tmpint = 0; // IDs are cell based
1362  out_stream.write(reinterpret_cast<char *>(&tmpint), sizeof(unsigned int));
1363 
1364  for (auto proc : make_range(mesh.n_processors()))
1365  {
1366  // We have to write exactly 8 bytes. This means that
1367  // the processor id can be up to 3 characters long, and
1368  // we pad it with blank characters on the end.
1369  std::ostringstream oss;
1370  oss << "proc_" << std::setw(3) << std::left << proc;
1371  out_stream.write(oss.str().c_str(), oss.str().size());
1372  }
1373 
1374  std::vector<unsigned int> proc_id (n_active_elem);
1375 
1376  unsigned int n=0;
1377 
1378  // We no longer write sub-elems in GMV, so just assign a
1379  // processor id value to each element.
1380  for (const auto & elem : mesh.active_element_ptr_range())
1381  proc_id[n++] = elem->processor_id() + 1;
1382 
1383  out_stream.write(reinterpret_cast<char *>(proc_id.data()),
1384  sizeof(unsigned int)*proc_id.size());
1385  }
1386 
1387  // If there are *any* variables at all in the system (including
1388  // p level, or arbitrary cell-based data)
1389  // to write, the gmv file needs to contain the word "variable"
1390  // on a line by itself.
1391  bool write_variable = false;
1392 
1393  // 1.) p-levels
1394  if (this->p_levels() && mesh_max_p_level)
1395  write_variable = true;
1396 
1397  // 2.) solution data
1398  if ((solution_names != nullptr) && (vec != nullptr))
1399  write_variable = true;
1400 
1401  // // 3.) cell-centered data - unsupported
1402  // if (!(this->_cell_centered_data.empty()))
1403  // write_variable = true;
1404 
1405  if (write_variable)
1406  {
1407  buffer = "variable";
1408  out_stream.write(buffer.c_str(), buffer.size());
1409  }
1410 
1411  // optionally write the partition information
1412  if (this->p_levels() && mesh_max_p_level)
1413  {
1414  unsigned int n_floats = n_active_elem;
1415  for (unsigned int i=0, d=mesh.mesh_dimension(); i != d; ++i)
1416  n_floats *= 2;
1417 
1418  std::vector<float> temp(n_floats);
1419 
1420  buffer = "p_level";
1421  out_stream.write(buffer.c_str(), buffer.size());
1422 
1423  unsigned int tempint = 0; // p levels are cell data
1424  out_stream.write(reinterpret_cast<char *>(&tempint), sizeof(unsigned int));
1425 
1426  unsigned int n=0;
1427  for (const auto & elem : mesh.active_element_ptr_range())
1428  for (unsigned int se=0, nse=elem->n_sub_elem(); se<nse; se++)
1429  temp[n++] = static_cast<float>( elem->p_level() );
1430 
1431  out_stream.write(reinterpret_cast<char *>(temp.data()),
1432  sizeof(float)*n_floats);
1433  }
1434 
1435 
1436  // optionally write cell-centered data
1437  if (!(this->_cell_centered_data.empty()))
1438  libMesh::err << "Cell-centered data not (yet) supported in binary I/O mode!" << std::endl;
1439 
1440 
1441 
1442 
1443  // optionally write the data
1444  if ((solution_names != nullptr) &&
1445  (vec != nullptr))
1446  {
1447  std::vector<float> temp(mesh.n_nodes());
1448 
1449  const unsigned int n_vars =
1450  cast_int<unsigned int>(solution_names->size());
1451 
1452  for (unsigned int c=0; c<n_vars; c++)
1453  {
1454 
1455 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1456  // for complex data, write three datasets
1457 
1458 
1459  // Real part
1460  buffer = "r_";
1461  out_stream.write(buffer.c_str(), buffer.size());
1462 
1463  buffer = (*solution_names)[c];
1464  out_stream.write(buffer.c_str(), buffer.size());
1465 
1466  unsigned int tempint = 1; // always do nodal data
1467  out_stream.write(reinterpret_cast<char *>(&tempint), sizeof(unsigned int));
1468 
1469  for (auto n : make_range(mesh.n_nodes()))
1470  temp[n] = static_cast<float>( (*vec)[n*n_vars + c].real() );
1471 
1472  out_stream.write(reinterpret_cast<char *>(temp.data()), sizeof(float)*mesh.n_nodes());
1473 
1474 
1475  // imaginary part
1476  buffer = "i_";
1477  out_stream.write(buffer.c_str(), buffer.size());
1478 
1479  buffer = (*solution_names)[c];
1480  out_stream.write(buffer.c_str(), buffer.size());
1481 
1482  out_stream.write(reinterpret_cast<char *>(&tempint), sizeof(unsigned int));
1483 
1484  for (auto n : make_range(mesh.n_nodes()))
1485  temp[n] = static_cast<float>( (*vec)[n*n_vars + c].imag() );
1486 
1487  out_stream.write(reinterpret_cast<char *>(temp.data()), sizeof(float)*mesh.n_nodes());
1488 
1489  // magnitude
1490  buffer = "a_";
1491  out_stream.write(buffer.c_str(), buffer.size());
1492  buffer = (*solution_names)[c];
1493  out_stream.write(buffer.c_str(), buffer.size());
1494 
1495  out_stream.write(reinterpret_cast<char *>(&tempint), sizeof(unsigned int));
1496 
1497  for (auto n : make_range(mesh.n_nodes()))
1498  temp[n] = static_cast<float>(std::abs((*vec)[n*n_vars + c]));
1499 
1500  out_stream.write(reinterpret_cast<char *>(temp.data()), sizeof(float)*mesh.n_nodes());
1501 
1502 #else
1503 
1504  buffer = (*solution_names)[c];
1505  out_stream.write(buffer.c_str(), buffer.size());
1506 
1507  unsigned int tempint = 1; // always do nodal data
1508  out_stream.write(reinterpret_cast<char *>(&tempint), sizeof(unsigned int));
1509 
1510  for (auto n : make_range(mesh.n_nodes()))
1511  temp[n] = static_cast<float>((*vec)[n*n_vars + c]);
1512 
1513  out_stream.write(reinterpret_cast<char *>(temp.data()), sizeof(float)*mesh.n_nodes());
1514 
1515 #endif
1516  }
1517  }
1518 
1519  // If we wrote any variables, we have to close the variable section now
1520  if (write_variable)
1521  {
1522  buffer = "endvars ";
1523  out_stream.write(buffer.c_str(), buffer.size());
1524  }
1525 
1526  // end the file
1527  buffer = "endgmv ";
1528  out_stream.write(buffer.c_str(), buffer.size());
1529 }
1530 
1531 
1532 
1533 
1534 
1535 
1536 
1537 
1538 
1539 void GMVIO::write_discontinuous_gmv (const std::string & name,
1540  const EquationSystems & es,
1541  const bool write_partitioning,
1542  const std::set<std::string> * system_names) const
1543 {
1544  std::vector<std::string> solution_names;
1545  std::vector<Number> v;
1546 
1547  // Get a reference to the mesh
1549 
1550  es.build_variable_names (solution_names, nullptr, system_names);
1551  es.build_discontinuous_solution_vector (v, system_names);
1552 
1553  // These are parallel_only functions
1554  const unsigned int n_active_elem = mesh.n_active_elem();
1555 
1556  if (mesh.processor_id() != 0)
1557  return;
1558 
1559  std::ofstream out_stream(name.c_str());
1560 
1561  libmesh_assert (out_stream.good());
1562 
1563  // Begin interfacing with the GMV data file
1564  {
1565 
1566  // write the nodes
1567  out_stream << "gmvinput ascii" << std::endl << std::endl;
1568 
1569  // Compute the total weight
1570  {
1571  unsigned int tw=0;
1572 
1573  for (const auto & elem : mesh.active_element_ptr_range())
1574  tw += elem->n_nodes();
1575 
1576  out_stream << "nodes " << tw << std::endl;
1577  }
1578 
1579 
1580 
1581  // Write all the x values
1582  {
1583  for (const auto & elem : mesh.active_element_ptr_range())
1584  for (const Node & node : elem->node_ref_range())
1585  out_stream << node(0) << " ";
1586 
1587  out_stream << std::endl;
1588  }
1589 
1590 
1591  // Write all the y values
1592  {
1593  for (const auto & elem : mesh.active_element_ptr_range())
1594  for (const Node & node : elem->node_ref_range())
1595 #if LIBMESH_DIM > 1
1596  out_stream << node(1) << " ";
1597 #else
1598  out_stream << 0. << " ";
1599 #endif
1600 
1601  out_stream << std::endl;
1602  }
1603 
1604 
1605  // Write all the z values
1606  {
1607  for (const auto & elem : mesh.active_element_ptr_range())
1608  for (const Node & node : elem->node_ref_range())
1609 #if LIBMESH_DIM > 2
1610  out_stream << node(2) << " ";
1611 #else
1612  out_stream << 0. << " ";
1613 #endif
1614 
1615  out_stream << std::endl << std::endl;
1616  }
1617  }
1618 
1619 
1620 
1621  {
1622  // write the connectivity
1623 
1624  out_stream << "cells " << n_active_elem << std::endl;
1625 
1626  unsigned int nn=1;
1627 
1628  switch (mesh.mesh_dimension())
1629  {
1630  case 1:
1631  {
1632  for (const auto & elem : mesh.active_element_ptr_range())
1633  for (unsigned int se=0, nse=elem->n_sub_elem(); se<nse; se++)
1634  {
1635  if ((elem->type() == EDGE2) ||
1636  (elem->type() == EDGE3) ||
1637  (elem->type() == EDGE4)
1638 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1639  || (elem->type() == INFEDGE2)
1640 #endif
1641  )
1642  {
1643  out_stream << "line 2" << std::endl;
1644  for (unsigned int i=0, enn=elem->n_nodes(); i<enn; i++)
1645  out_stream << nn++ << " ";
1646 
1647  }
1648  else
1649  libmesh_error_msg("Unsupported 1D element type: " << Utility::enum_to_string(elem->type()));
1650 
1651  out_stream << std::endl;
1652  }
1653 
1654  break;
1655  }
1656 
1657  case 2:
1658  {
1659  for (const auto & elem : mesh.active_element_ptr_range())
1660  for (unsigned int se=0, nse=elem->n_sub_elem(); se<nse; se++)
1661  {
1662  if ((elem->type() == QUAD4) ||
1663  (elem->type() == QUAD8) || // Note: QUAD8 will be output as one central quad and
1664  // four surrounding triangles (though they will be written
1665  // to GMV as QUAD4s).
1666  (elem->type() == QUAD9)
1667 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1668  || (elem->type() == INFQUAD4)
1669  || (elem->type() == INFQUAD6)
1670 #endif
1671  )
1672  {
1673  out_stream << "quad 4" << std::endl;
1674  for (unsigned int i=0, enn=elem->n_nodes(); i<enn; i++)
1675  out_stream << nn++ << " ";
1676 
1677  }
1678  else if ((elem->type() == TRI3) ||
1679  (elem->type() == TRI6))
1680  {
1681  out_stream << "tri 3" << std::endl;
1682  for (unsigned int i=0, enn=elem->n_nodes(); i<enn; i++)
1683  out_stream << nn++ << " ";
1684 
1685  }
1686  else
1687  libmesh_error_msg("Unsupported 2D element type: " << Utility::enum_to_string(elem->type()));
1688 
1689  out_stream << std::endl;
1690  }
1691 
1692  break;
1693  }
1694 
1695 
1696  case 3:
1697  {
1698  for (const auto & elem : mesh.active_element_ptr_range())
1699  for (unsigned int se=0, nse=elem->n_sub_elem(); se<nse; se++)
1700  {
1701  if ((elem->type() == HEX8) ||
1702  (elem->type() == HEX20) ||
1703  (elem->type() == HEX27)
1704 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1705  || (elem->type() == INFHEX8)
1706  || (elem->type() == INFHEX16)
1707  || (elem->type() == INFHEX18)
1708 #endif
1709  )
1710  {
1711  out_stream << "phex8 8" << std::endl;
1712  for (unsigned int i=0, enn=elem->n_nodes(); i<enn; i++)
1713  out_stream << nn++ << " ";
1714  }
1715  else if ((elem->type() == PRISM6) ||
1716  (elem->type() == PRISM15) ||
1717  (elem->type() == PRISM18)
1718 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1719  || (elem->type() == INFPRISM6)
1720  || (elem->type() == INFPRISM12)
1721 #endif
1722  )
1723  {
1724  out_stream << "pprism6 6" << std::endl;
1725  for (unsigned int i=0, enn=elem->n_nodes(); i<enn; i++)
1726  out_stream << nn++ << " ";
1727  }
1728  else if ((elem->type() == TET4) ||
1729  (elem->type() == TET10))
1730  {
1731  out_stream << "tet 4" << std::endl;
1732  for (unsigned int i=0, enn=elem->n_nodes(); i<enn; i++)
1733  out_stream << nn++ << " ";
1734  }
1735  else
1736  libmesh_error_msg("Unsupported 3D element type: " << Utility::enum_to_string(elem->type()));
1737 
1738  out_stream << std::endl;
1739  }
1740 
1741  break;
1742  }
1743 
1744  default:
1745  libmesh_error_msg("Unsupported mesh dimension: " << mesh.mesh_dimension());
1746  }
1747 
1748  out_stream << std::endl;
1749  }
1750 
1751 
1752 
1753  // optionally write the partition information
1754  if (write_partitioning)
1755  {
1756  libmesh_error_msg_if(_write_subdomain_id_as_material,
1757  "Not yet supported in GMVIO::write_discontinuous_gmv");
1758 
1759  out_stream << "material "
1760  << mesh.n_processors()
1761  << " 0"<< std::endl;
1762 
1763  for (auto proc : make_range(mesh.n_processors()))
1764  out_stream << "proc_" << proc << std::endl;
1765 
1766  for (const auto & elem : mesh.active_element_ptr_range())
1767  out_stream << elem->processor_id()+1 << std::endl;
1768 
1769  out_stream << std::endl;
1770  }
1771 
1772 
1773  // Writing cell-centered data is not yet supported in discontinuous GMV files.
1774  if (!(this->_cell_centered_data.empty()))
1775  {
1776  libMesh::err << "Cell-centered data not (yet) supported for discontinuous GMV files!" << std::endl;
1777  }
1778 
1779 
1780 
1781  // write the data
1782  {
1783  const unsigned int n_vars =
1784  cast_int<unsigned int>(solution_names.size());
1785 
1786  // libmesh_assert_equal_to (v.size(), tw*n_vars);
1787 
1788  out_stream << "variable" << std::endl;
1789 
1790 
1791  for (unsigned int c=0; c<n_vars; c++)
1792  {
1793 
1794 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1795 
1796  // in case of complex data, write _tree_ data sets
1797  // for each component
1798 
1799  // this is the real part
1800  out_stream << "r_" << solution_names[c] << " 1" << std::endl;
1801  for (const auto & elem : mesh.active_element_ptr_range())
1802  for (auto n : elem->node_index_range())
1803  out_stream << v[(n++)*n_vars + c].real() << " ";
1804  out_stream << std::endl << std::endl;
1805 
1806 
1807  // this is the imaginary part
1808  out_stream << "i_" << solution_names[c] << " 1" << std::endl;
1809  for (const auto & elem : mesh.active_element_ptr_range())
1810  for (auto n : elem->node_index_range())
1811  out_stream << v[(n++)*n_vars + c].imag() << " ";
1812  out_stream << std::endl << std::endl;
1813 
1814  // this is the magnitude
1815  out_stream << "a_" << solution_names[c] << " 1" << std::endl;
1816  for (const auto & elem : mesh.active_element_ptr_range())
1817  for (auto n : elem->node_index_range())
1818  out_stream << std::abs(v[(n++)*n_vars + c]) << " ";
1819  out_stream << std::endl << std::endl;
1820 
1821 #else
1822 
1823  out_stream << solution_names[c] << " 1" << std::endl;
1824  {
1825  unsigned int nn=0;
1826 
1827  for (const auto & elem : mesh.active_element_ptr_range())
1828  for (unsigned int i=0, enn=elem->n_nodes(); i<enn; i++)
1829  out_stream << v[(nn++)*n_vars + c] << " ";
1830  }
1831  out_stream << std::endl << std::endl;
1832 
1833 #endif
1834 
1835  }
1836 
1837  out_stream << "endvars" << std::endl;
1838  }
1839 
1840 
1841  // end of the file
1842  out_stream << std::endl << "endgmv" << std::endl;
1843 }
1844 
1845 
1846 
1847 
1848 
1849 void GMVIO::add_cell_centered_data (const std::string & cell_centered_data_name,
1850  const std::vector<Real> * cell_centered_data_vals)
1851 {
1852  libmesh_assert(cell_centered_data_vals);
1853 
1854  // Make sure there are *at least* enough entries for all the active elements.
1855  // There can also be entries for inactive elements, they will be ignored.
1856  // libmesh_assert_greater_equal (cell_centered_data_vals->size(),
1857  // MeshOutput<MeshBase>::mesh().n_active_elem());
1858  this->_cell_centered_data[cell_centered_data_name] = cell_centered_data_vals;
1859 }
1860 
1861 
1862 
1863 
1864 
1865 
1866 void GMVIO::read (const std::string & name)
1867 {
1868  // This is a serial-only process for now;
1869  // the Mesh should be read on processor 0 and
1870  // broadcast later
1871  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
1872 
1873  _next_elem_id = 0;
1874 
1875  libmesh_experimental();
1876 
1877 #ifndef LIBMESH_HAVE_GMV
1878 
1879  libmesh_error_msg("Cannot read GMV file " << name << " without the GMV API.");
1880 
1881 #else
1882  // We use the file-scope global variable eletypes for mapping nodes
1883  // from GMV to libmesh indices, so initialize that data now.
1884  init_eletypes();
1885 
1886  // Clear the mesh so we are sure to start from a pristine state.
1888  mesh.clear();
1889 
1890  // Keep track of what kinds of elements this file contains
1891  elems_of_dimension.clear();
1892  elems_of_dimension.resize(4, false);
1893 
1894  // It is apparently possible for gmv files to contain
1895  // a "fromfile" directive (?) But we currently don't make
1896  // any use of this feature in LibMesh. Nonzero return val
1897  // from any function usually means an error has occurred.
1898  int ierr = GMVLib::gmvread_open_fromfileskip(const_cast<char *>(name.c_str()));
1899  libmesh_error_msg_if(ierr != 0, "GMVLib::gmvread_open_fromfileskip failed!");
1900 
1901  // Loop through file until GMVEND.
1902  int iend = 0;
1903  while (iend == 0)
1904  {
1905  GMVLib::gmvread_data();
1906 
1907  // Check for GMVEND.
1908  if (GMVLib::gmv_data.keyword == GMVEND)
1909  {
1910  iend = 1;
1911  GMVLib::gmvread_close();
1912  break;
1913  }
1914 
1915  // Check for GMVERROR.
1916  libmesh_error_msg_if(GMVLib::gmv_data.keyword == GMVERROR,
1917  "Encountered GMVERROR while reading!");
1918 
1919  // Process the data.
1920  switch (GMVLib::gmv_data.keyword)
1921  {
1922  case NODES:
1923  {
1924  if (GMVLib::gmv_data.num2 == NODES)
1925  this->_read_nodes();
1926 
1927  else
1928  libmesh_error_msg_if(GMVLib::gmv_data.num2 == NODE_V,
1929  "Unsupported GMV data type NODE_V!");
1930 
1931  break;
1932  }
1933 
1934  case CELLS:
1935  {
1936  // Read 1 cell at a time
1937  this->_read_one_cell();
1938  break;
1939  }
1940 
1941  case MATERIAL:
1942  {
1943  // keyword == 6
1944  // These are the materials, which we use to specify the mesh
1945  // partitioning.
1946  this->_read_materials();
1947  break;
1948  }
1949 
1950  case VARIABLE:
1951  {
1952  // keyword == 8
1953  // This is a field variable.
1954 
1955  // Check to see if we're done reading variables and break out.
1956  if (GMVLib::gmv_data.datatype == ENDKEYWORD)
1957  {
1958  break;
1959  }
1960 
1961  if (GMVLib::gmv_data.datatype == NODE)
1962  {
1963  this->_read_var();
1964  break;
1965  }
1966 
1967  else
1968  {
1969  libMesh::err << "Warning: Skipping variable: "
1970  << GMVLib::gmv_data.name1
1971  << " which is of unsupported GMV datatype "
1972  << GMVLib::gmv_data.datatype
1973  << ". Nodal field data is currently the only type currently supported."
1974  << std::endl;
1975  break;
1976  }
1977 
1978  }
1979 
1980  default:
1981  libmesh_error_msg("Encountered unknown GMV keyword " << GMVLib::gmv_data.keyword);
1982 
1983  } // end switch
1984  } // end while
1985 
1986  // Set the mesh dimension to the largest encountered for an element
1987  for (unsigned char i=0; i!=4; ++i)
1988  if (elems_of_dimension[i])
1990 
1991 #if LIBMESH_DIM < 3
1992  libmesh_error_msg_if(mesh.mesh_dimension() > LIBMESH_DIM,
1993  "Cannot open dimension "
1994  << mesh.mesh_dimension()
1995  << " mesh file when configured without "
1996  << mesh.mesh_dimension()
1997  << "D support.");
1998 #endif
1999 
2000  // Done reading in the mesh, now call find_neighbors, etc.
2001  // mesh.find_neighbors();
2002 
2003  // Don't allow renumbering of nodes and elements when calling
2004  // prepare_for_use(). It is usually confusing for users when the
2005  // Mesh gets renumbered automatically, since sometimes there are
2006  // other parts of the simulation which rely on the original
2007  // ordering.
2008  mesh.allow_renumbering(false);
2010 #endif
2011 }
2012 
2013 
2014 
2015 
2017 {
2018 #ifdef LIBMESH_HAVE_GMV
2019 
2020  // Copy all the variable's values into a local storage vector.
2021  _nodal_data.emplace(std::string(GMVLib::gmv_data.name1),
2022  std::vector<Number>(GMVLib::gmv_data.doubledata1, GMVLib::gmv_data.doubledata1+GMVLib::gmv_data.num));
2023 #endif
2024 }
2025 
2026 
2027 
2029 {
2030 #ifdef LIBMESH_HAVE_GMV
2031 
2032  // LibMesh assigns materials on a per-cell basis
2033  libmesh_assert_equal_to (GMVLib::gmv_data.datatype, CELL);
2034 
2035  // Material names: LibMesh has no use for these currently...
2036  // for (int i = 0; i < GMVLib::gmv_data.num; i++)
2037  // {
2038  // // Build a 32-char string from the appropriate entries
2039  // std::string mat_string(&GMVLib::gmv_data.chardata1[i*33], 32);
2040  // }
2041 
2042  for (int i = 0; i < GMVLib::gmv_data.nlongdata1; i++)
2043  MeshInput<MeshBase>::mesh().elem_ref(i).processor_id() =
2044  cast_int<processor_id_type>(GMVLib::gmv_data.longdata1[i]-1);
2045 
2046 #endif
2047 }
2048 
2049 
2050 
2051 
2053 {
2054 #ifdef LIBMESH_HAVE_GMV
2055  // LibMesh writes UNSTRUCT=100 node data
2056  libmesh_assert_equal_to (GMVLib::gmv_data.datatype, UNSTRUCT);
2057 
2058  // The nodal data is stored in gmv_data.doubledata{1,2,3}
2059  // and is nnodes long
2060  for (int i = 0; i < GMVLib::gmv_data.num; i++)
2061  {
2062  // Add the point to the Mesh
2063  MeshInput<MeshBase>::mesh().add_point(Point(GMVLib::gmv_data.doubledata1[i],
2064  GMVLib::gmv_data.doubledata2[i],
2065  GMVLib::gmv_data.doubledata3[i]), i);
2066  }
2067 #endif
2068 }
2069 
2070 
2072 {
2073 #ifdef LIBMESH_HAVE_GMV
2074  // This is either a REGULAR=111 cell or
2075  // the ENDKEYWORD=207 of the cells
2076 #ifndef NDEBUG
2077  bool recognized =
2078  (GMVLib::gmv_data.datatype==REGULAR) ||
2079  (GMVLib::gmv_data.datatype==ENDKEYWORD);
2080 #endif
2081  libmesh_assert (recognized);
2082 
2084 
2085  if (GMVLib::gmv_data.datatype == REGULAR)
2086  {
2087  // We need a mapping from GMV element types to LibMesh
2088  // ElemTypes. Basically the reverse of the eletypes
2089  // std::map above.
2090  //
2091  // FIXME: Since Quad9's apparently don't exist for GMV, and since
2092  // In general we write linear sub-elements to GMV files, we need
2093  // to be careful to read back in exactly what we wrote out...
2094  //
2095  // The gmv_data.name1 field is padded with blank characters when
2096  // it is read in by GMV, so the function that converts it to the
2097  // libmesh element type needs to take that into account.
2098  ElemType type = this->gmv_elem_to_libmesh_elem(GMVLib::gmv_data.name1);
2099 
2100  auto elem = Elem::build(type);
2101  elem->set_id(_next_elem_id++);
2102 
2103  // Get the ElementDefinition object for this element type
2104  const ElementDefinition & eledef = eletypes[type];
2105 
2106  // Print out the connectivity information for
2107  // this cell.
2108  for (int i=0; i<GMVLib::gmv_data.num2; i++)
2109  {
2110  // Map index i to GMV's numbering scheme
2111  unsigned mapped_i = eledef.node_map[i];
2112 
2113  // Note: Node numbers (as stored in libmesh) are 1-based
2114  elem->set_node
2115  (i, mesh.node_ptr
2116  (cast_int<dof_id_type>(GMVLib::gmv_data.longdata1[mapped_i]-1)));
2117  }
2118 
2119  elems_of_dimension[elem->dim()] = true;
2120 
2121  // Add the newly-created element to the mesh
2122  mesh.add_elem(std::move(elem));
2123  }
2124 
2125 
2126  if (GMVLib::gmv_data.datatype == ENDKEYWORD)
2127  {
2128  // There isn't a cell to read, so we just return
2129  return;
2130  }
2131 
2132 #endif
2133 }
2134 
2135 
2137 {
2138  // Erase any whitespace padding in name coming from gmv before performing comparison.
2139  elemname.erase(std::remove_if(elemname.begin(), elemname.end(),
2140  [](unsigned char const c){return std::isspace(c);}),
2141  elemname.end());
2142  return libmesh_map_find(_reading_element_map, elemname);
2143 }
2144 
2145 
2146 
2147 
2149 {
2150  // Check for easy return if there isn't any nodal data
2151  if (_nodal_data.empty())
2152  {
2153  libMesh::err << "Unable to copy nodal solution: No nodal "
2154  << "solution has been read in from file." << std::endl;
2155  return;
2156  }
2157 
2158  // Be sure there is at least one system
2159  libmesh_assert (es.n_systems());
2160 
2161  // Keep track of variable names which have been found and
2162  // copied already. This could be used to prevent us from
2163  // e.g. copying the same var into 2 different systems ...
2164  // but this seems unlikely. Also, it is used to tell if
2165  // any variables which were read in were not successfully
2166  // copied to the EquationSystems.
2167  std::set<std::string> vars_copied;
2168 
2169  // For each entry in the nodal data map, try to find a system
2170  // that has the same variable key name.
2171  for (auto sys : make_range(es.n_systems()))
2172  {
2173  // Get a generic reference to the current System
2174  System & system = es.get_system(sys);
2175 
2176  // For each var entry in the _nodal_data map, try to find
2177  // that var in the system
2178  for (const auto & [var_name, vec] : _nodal_data)
2179  {
2180  if (system.has_variable(var_name))
2181  {
2182  // Check if there are as many nodes in the mesh as there are entries
2183  // in the stored nodal data vector
2184  libmesh_assert_equal_to (vec.size(), MeshInput<MeshBase>::mesh().n_nodes());
2185 
2186  const unsigned int var_num = system.variable_number(var_name);
2187 
2188  // The only type of nodal data we can read in from GMV is for
2189  // linear LAGRANGE type elements.
2190  const FEType & fe_type = system.variable_type(var_num);
2191  if ((fe_type.order.get_order() != FIRST) || (fe_type.family != LAGRANGE))
2192  {
2193  libMesh::err << "Only FIRST-order LAGRANGE variables can be read from GMV files. "
2194  << "Skipping variable " << var_name << std::endl;
2195  break;
2196  }
2197 
2198 
2199  // Loop over the stored vector's entries, inserting them into
2200  // the System's solution if appropriate.
2201  for (dof_id_type i=0,
2202  sz = cast_int<dof_id_type>(vec.size());
2203  i != sz; ++i)
2204  {
2205  // Since this var came from a GMV file, the index i corresponds to
2206  // the (single) DOF value of the current variable for node i.
2207  const unsigned int dof_index =
2208  MeshInput<MeshBase>::mesh().node_ptr(i)->dof_number(sys, // system #
2209  var_num, // var #
2210  0); // component #, always zero for LAGRANGE
2211 
2212  // If the dof_index is local to this processor, set the value
2213  if ((dof_index >= system.solution->first_local_index()) &&
2214  (dof_index < system.solution->last_local_index()))
2215  system.solution->set (dof_index, vec[i]);
2216  } // end loop over my GMVIO's copy of the solution
2217 
2218  // Add the most recently copied var to the set of copied vars
2219  vars_copied.insert (var_name);
2220  } // end if (system.has_variable)
2221  } // end for loop over _nodal_data
2222 
2223  // Communicate parallel values before going to the next system.
2224  system.solution->close();
2225  system.update();
2226  } // end loop over all systems
2227 
2228 
2229 
2230  // Warn the user if any GMV variables were not successfully copied over to the EquationSystems object
2231  for (const auto & pr : _nodal_data)
2232  if (vars_copied.find(pr.first) == vars_copied.end())
2233  libMesh::err << "Warning: Variable "
2234  << pr.first
2235  << " was not copied to the EquationSystems object."
2236  << std::endl;
2237 }
2238 
2239 } // namespace libMesh
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
OStreamProxy err
const MT & mesh() const
Definition: mesh_output.h:259
virtual void read(const std::string &mesh_file) override
This method implements reading a mesh from a specified file.
Definition: gmv_io.C:1866
void _read_var()
Definition: gmv_io.C:2016
FEFamily family
The type of finite element.
Definition: fe_type.h:221
ElemType
Defines an enum for geometric element types.
This is the EquationSystems class.
void _read_nodes()
Helper functions for reading nodes/cells from a GMV file.
Definition: gmv_io.C:2052
void build_variable_names(std::vector< std::string > &var_names, const FEType *type=nullptr, const std::set< std::string > *system_names=nullptr) const
Fill the input vector var_names with the names of the variables for each system.
virtual dof_id_type n_active_elem() const =0
A Node is like a Point, but with more information.
Definition: node.h:52
unsigned int n_systems() const
static std::map< std::string, ElemType > _reading_element_map
Static map from string -> ElementType for use during reading.
Definition: gmv_io.h:242
virtual void write(const std::string &) override
This method implements writing a mesh to a specified file.
Definition: gmv_io.C:271
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use...
Definition: mesh_base.h:1196
void write_binary(const std::string &, const std::vector< Number > *=nullptr, const std::vector< std::string > *=nullptr)
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition: gmv_io.C:1221
void build_discontinuous_solution_vector(std::vector< Number > &soln, const std::set< std::string > *system_names=nullptr, const std::vector< std::string > *var_names=nullptr, bool vertices_only=false, bool add_sides=false) const
Fill the input vector soln with solution values.
std::vector< bool > elems_of_dimension
A vector of bools describing what dimension elements have been encountered when reading a mesh...
Definition: mesh_input.h:107
unsigned int _next_elem_id
Definition: gmv_io.h:231
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
Definition: mesh_base.C:741
MeshBase & mesh
unsigned int & ascii_precision()
Return/set the precision to use when writing ASCII files.
Definition: mesh_output.h:269
OrderWrapper order
The approximation order of the element.
Definition: fe_type.h:215
This class defines an abstract interface for Mesh output.
Definition: mesh_output.h:53
The libMesh namespace provides an interface to certain functionality in the library.
bool & partitioning()
Flag indicating whether or not to write the partitioning information for the mesh.
Definition: gmv_io.h:107
const T_sys & get_system(std::string_view name) const
std::map< std::string, std::vector< Number > > _nodal_data
Definition: gmv_io.h:236
This is the MeshBase class.
Definition: mesh_base.h:75
bool & binary()
Flag indicating whether or not to write a binary file.
Definition: gmv_io.h:95
unsigned int variable_number(std::string_view var) const
Definition: system.C:1587
virtual void write_nodal_data(const std::string &, const std::vector< Number > &, const std::vector< std::string > &) override
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition: gmv_io.C:281
bool & write_subdomain_id_as_material()
Flag to write element subdomain_id&#39;s as GMV "materials" instead of element processor_id&#39;s.
Definition: gmv_io.h:114
ElemType gmv_elem_to_libmesh_elem(std::string elemname)
Definition: gmv_io.C:2136
std::map< std::string, const std::vector< Real > *> _cell_centered_data
Storage for arbitrary cell-centered data.
Definition: gmv_io.h:225
bool has_variable(std::string_view var) const
Definition: system.C:1580
processor_id_type n_processors() const
static std::map< std::string, ElemType > build_reading_element_map()
Static function used to build the _reading_element_map.
Definition: gmv_io.C:209
This class defines an abstract interface for Mesh input.
Definition: mesh_base.h:57
unsigned int n_vars
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:96
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:447
bool _write_subdomain_id_as_material
Flag to write element subdomain_id&#39;s as GMV "materials" instead of element processor_id&#39;s.
Definition: gmv_io.h:207
bool & p_levels()
Flag indicating whether or not to write p level information for p refined meshes. ...
Definition: gmv_io.h:126
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1590
libmesh_assert(ctx)
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition: mesh_base.h:275
void copy_nodal_solution(EquationSystems &es)
If we read in a nodal solution while reading in a mesh, we can attempt to copy that nodal solution in...
Definition: gmv_io.C:2148
void _read_materials()
Definition: gmv_io.C:2028
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:902
void write_ascii_old_impl(const std::string &, const std::vector< Number > *=nullptr, const std::vector< std::string > *=nullptr)
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition: gmv_io.C:565
int get_order() const
Explicitly request the order as an int.
Definition: fe_type.h:80
std::string enum_to_string(const T e)
unsigned int n_partitions() const
Definition: mesh_base.h:1345
bool & subdivide_second_order()
Flag indicating whether or not to subdivide second order elements.
Definition: gmv_io.h:120
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:497
const FEType & variable_type(const unsigned int i) const
Definition: system.h:2495
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void write_ascii_new_impl(const std::string &, const std::vector< Number > *=nullptr, const std::vector< std::string > *=nullptr)
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition: gmv_io.C:295
GMVIO(const MeshBase &)
Constructor.
Definition: gmv_io.C:242
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
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...
Definition: int_range.h:140
dof_id_type n_active_sub_elem() const
Same as n_sub_elem(), but only counts active elements.
Definition: mesh_base.C:1052
unsigned int mesh_dimension() const
Definition: mesh_base.C:354
void _read_one_cell()
Definition: gmv_io.C:2071
void add_cell_centered_data(const std::string &cell_centered_data_name, const std::vector< Real > *cell_centered_data_vals)
Takes a vector of cell-centered data to be plotted.
Definition: gmv_io.C:1849
virtual const Point & point(const dof_id_type i) const =0
Definition: gmv_io.C:41
virtual dof_id_type max_node_id() const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
processor_id_type processor_id() const
static ElemType first_order_equivalent_type(const ElemType et)
Definition: elem.C:3069
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
void write_discontinuous_gmv(const std::string &name, const EquationSystems &es, const bool write_partitioning, const std::set< std::string > *system_names=nullptr) const
Writes a GMV file with discontinuous data.
Definition: gmv_io.C:1539
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:117
virtual dof_id_type n_nodes() const =0
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)
A useful inline function which replaces the macros used previously.
uint8_t dof_id_type
Definition: id_types.h:67