libMesh
Loading...
Searching...
No Matches
gmv_io.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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
41namespace GMVLib
42{
43extern "C"
44{
45#include "gmvread.h"
46}
47}
48#endif
49
50// anonymous namespace to hold local data
51namespace
52{
53using namespace libMesh;
54
63struct 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.
76std::map<ElemType, ElementDefinition> eletypes;
77
78// Helper function to fill up eletypes map
79void 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
100void 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
200namespace libMesh
201{
202
203// Initialize the static data members by calling the static build functions.
204std::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.
209std::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
271void 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
281void 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
295void 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
565void 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 {
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
1221void 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
1539void 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
1849void 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
1866void 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
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
unsigned int n_vars
void ErrorVector unsigned int
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:442
static ElemType first_order_equivalent_type(const ElemType et)
Definition elem.C:3099
This is the EquationSystems class.
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.
unsigned int n_systems() const
const T_sys & get_system(std::string_view name) const
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.
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
OrderWrapper order
The approximation order of the element (at 0 p-refinement level).
Definition fe_type.h:203
FEFamily family
The type of finite element.
Definition fe_type.h:228
bool & partitioning()
Flag indicating whether or not to write the partitioning information for the mesh.
Definition gmv_io.h:107
static std::map< std::string, ElemType > _reading_element_map
Static map from string -> ElementType for use during reading.
Definition gmv_io.h:242
bool & write_subdomain_id_as_material()
Flag to write element subdomain_id's as GMV "materials" instead of element processor_id's.
Definition gmv_io.h:114
bool & p_levels()
Flag indicating whether or not to write p level information for p refined meshes.
Definition gmv_io.h:126
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_one_cell()
Definition gmv_io.C:2071
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
void _read_var()
Definition gmv_io.C:2016
void _read_nodes()
Helper functions for reading nodes/cells from a GMV file.
Definition gmv_io.C:2052
std::map< std::string, std::vector< Number > > _nodal_data
Definition gmv_io.h:236
bool & binary()
Flag indicating whether or not to write a binary file.
Definition gmv_io.h:95
virtual void write(const std::string &) override
This method implements writing a mesh to a specified file.
Definition gmv_io.C:271
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
virtual void read(const std::string &mesh_file) override
This method implements reading a mesh from a specified file.
Definition gmv_io.C:1866
bool & subdivide_second_order()
Flag indicating whether or not to subdivide second order elements.
Definition gmv_io.h:120
ElemType gmv_elem_to_libmesh_elem(std::string elemname)
Definition gmv_io.C:2136
void _read_materials()
Definition gmv_io.C:2028
GMVIO(const MeshBase &)
Constructor.
Definition gmv_io.C:242
static std::map< std::string, ElemType > build_reading_element_map()
Static function used to build the _reading_element_map.
Definition gmv_io.C:209
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
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
unsigned int _next_elem_id
Definition gmv_io.h:231
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's as GMV "materials" instead of element processor_id's.
Definition gmv_io.h:207
std::map< std::string, const std::vector< Real > * > _cell_centered_data
Storage for arbitrary cell-centered data.
Definition gmv_io.h:225
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
This is the MeshBase class.
Definition mesh_base.h:81
virtual const Point & point(const dof_id_type i) const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
unsigned int mesh_dimension() const
Definition mesh_base.C:430
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:1355
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (or read) mesh for use.
Definition mesh_base.C:824
dof_id_type n_active_sub_elem() const
Same as n_sub_elem(), but only counts active elements.
Definition mesh_base.C:1263
virtual dof_id_type n_nodes() const =0
virtual dof_id_type max_node_id() const =0
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition mesh_base.h:423
unsigned int n_partitions() const
Definition mesh_base.h:1526
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition mesh_base.C:1036
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
virtual dof_id_type n_active_elem() const =0
This class defines an abstract interface for Mesh input.
Definition mesh_input.h:49
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
This class defines an abstract interface for Mesh output.
Definition mesh_output.h:54
unsigned int & ascii_precision()
Return/set the precision to use when writing ASCII files.
const MT & mesh() const
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
A Node is like a Point, but with more information.
Definition node.h:55
int get_order() const
Explicitly request the order as an int.
Definition fe_type.h:80
processor_id_type processor_id() const
processor_id_type n_processors() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
const FEType & variable_type(const unsigned int i) const
Definition system.C:2721
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition system.h:1655
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition system.C:498
unsigned int variable_number(std::string_view var) const
Definition system.C:1398
bool has_variable(std::string_view var) const
Definition system.C:1393
MeshBase & mesh
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
OStreamProxy err
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:153
ElemType
Defines an enum for geometric element types.
libmesh_assert(ctx)
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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:176