libMesh
Loading...
Searching...
No Matches
vtk_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
19// Local includes
20#include "libmesh/libmesh_config.h"
21#include "libmesh/vtk_io.h"
22#include "libmesh/mesh_base.h"
23#include "libmesh/equation_systems.h"
24#include "libmesh/numeric_vector.h"
25#include "libmesh/system.h"
26#include "libmesh/node.h"
27#include "libmesh/elem.h"
28#include "libmesh/enum_io_package.h"
29#include "libmesh/utility.h"
30
31#ifdef LIBMESH_HAVE_VTK
32
33// I get a lot of "warning: extra ';' inside a class [-Wextra-semi]" from clang
34// on VTK header files.
35#include "libmesh/ignore_warnings.h"
36
37#include "vtkXMLUnstructuredGridReader.h"
38#include "vtkXMLPUnstructuredGridReader.h"
39#include "vtkXMLUnstructuredGridWriter.h"
40#include "vtkXMLPUnstructuredGridWriter.h"
41#include "vtkUnstructuredGrid.h"
42#include "vtkIntArray.h"
43#include "vtkCellArray.h"
44#include "vtkCellData.h"
45#include "vtkDoubleArray.h"
46#include "vtkGenericCell.h"
47#include "vtkPointData.h"
48#include "vtkPoints.h"
49#include "vtkSmartPointer.h"
50
51#ifdef LIBMESH_HAVE_MPI
52#include "vtkMPI.h"
53#include "vtkMPICommunicator.h"
54#include "vtkMPIController.h"
55#endif
56
57#include "libmesh/restore_warnings.h"
58
59// C++ includes
60#include <fstream>
61
62
63// A convenient macro for comparing VTK versions. Returns 1 if the
64// current VTK version is < major.minor.subminor and zero otherwise.
65//
66// It relies on the VTK version numbers detected during configure. Note that if
67// LIBMESH_HAVE_VTK is not defined, none of the LIBMESH_DETECTED_VTK_VERSION_* variables will
68// be defined either.
69#define VTK_VERSION_LESS_THAN(major,minor,subminor) \
70 ((LIBMESH_DETECTED_VTK_VERSION_MAJOR < (major) || \
71 (LIBMESH_DETECTED_VTK_VERSION_MAJOR == (major) && (LIBMESH_DETECTED_VTK_VERSION_MINOR < (minor) || \
72 (LIBMESH_DETECTED_VTK_VERSION_MINOR == (minor) && \
73 LIBMESH_DETECTED_VTK_VERSION_SUBMINOR < (subminor))))) ? 1 : 0)
74
75#endif // LIBMESH_HAVE_VTK
76
77
78
79namespace libMesh
80{
81
82// Constructor for reading
84 MeshInput<MeshBase> (mesh, /*is_parallel_format=*/true),
85 MeshOutput<MeshBase>(mesh, /*is_parallel_format=*/true)
86#ifdef LIBMESH_HAVE_VTK
87 ,_compress(false)
88#endif
89{
90}
91
92
93
94// Constructor for writing
95VTKIO::VTKIO (const MeshBase & mesh) :
96 MeshOutput<MeshBase>(mesh, /*is_parallel_format=*/true)
97#ifdef LIBMESH_HAVE_VTK
98 ,_compress(false)
99#endif
100{
101}
102
103
104
105// Output the mesh without solutions to a .pvtu file
106void VTKIO::write (const std::string & name)
107{
108 std::vector<Number> soln;
109 std::vector<std::string> names;
110 this->write_nodal_data(name, soln, names);
111}
112
113
114
115// The rest of the file is wrapped in ifdef LIBMESH_HAVE_VTK except for
116// a couple of "stub" functions at the bottom.
117#ifdef LIBMESH_HAVE_VTK
118
119// Initialize the static _element_maps map.
120std::map<ElemMappingType, VTKIO::ElementMaps> VTKIO::_element_maps = VTKIO::build_element_maps();
121
122// Static function which constructs the ElementMaps object.
123std::map<ElemMappingType, VTKIO::ElementMaps> VTKIO::build_element_maps()
124{
125 // Object to be filled up
126 std::map<ElemMappingType, VTKIO::ElementMaps> all_maps;
127 ElementMaps em; // Lagrange element maps
128
129 em.associate(EDGE2, VTK_LINE);
130 em.associate(EDGE3, VTK_QUADRATIC_EDGE);
131 em.associate(TRI3, VTK_TRIANGLE);
132 em.associate(TRI6, VTK_QUADRATIC_TRIANGLE);
133 em.associate(QUAD4, VTK_QUAD);
134 em.associate(QUAD8, VTK_QUADRATIC_QUAD);
135 em.associate(TET4, VTK_TETRA);
136 em.associate(TET10, VTK_QUADRATIC_TETRA);
137 em.associate(HEX8, VTK_HEXAHEDRON);
138 em.associate(HEX20, VTK_QUADRATIC_HEXAHEDRON);
139 em.associate(HEX27, VTK_TRIQUADRATIC_HEXAHEDRON);
140 em.associate(PRISM6, VTK_WEDGE);
141 em.associate(PRISM15, VTK_QUADRATIC_WEDGE);
142 em.associate(PRISM18, VTK_BIQUADRATIC_QUADRATIC_WEDGE);
143 em.associate(PYRAMID5, VTK_PYRAMID);
144
145 // VTK_BIQUADRATIC_QUAD has been around since VTK 5.0
146#if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0)
147 em.associate(QUAD9, VTK_BIQUADRATIC_QUAD);
148#endif
149
150 // TRI3SUBDIVISION is for writing only
151 em.writing_map[TRI3SUBDIVISION] = VTK_TRIANGLE;
152 all_maps[ElemMappingType::LAGRANGE_MAP] = em;
153
154
155 // VTK_BEZIER_* types were introduced in VTK 9.0
156#if VTK_VERSION_LESS_THAN(9,0,0)
157 // Revert back to previous behavior when using an older version of VTK
159#else
160 ElementMaps bem; // Rational Bernstein element maps
161 bem.associate(EDGE2, VTK_LINE);
162 bem.associate(EDGE3, VTK_BEZIER_CURVE);
163 bem.associate(TRI3, VTK_TRIANGLE);
164 bem.associate(TRI6, VTK_BEZIER_TRIANGLE);
165 bem.associate(QUAD4, VTK_QUAD);
166 bem.associate(QUAD8, VTK_QUADRATIC_QUAD);
167 bem.associate(QUAD9, VTK_BEZIER_QUADRILATERAL);
168 bem.associate(TET4, VTK_TETRA);
169 bem.associate(TET10, VTK_QUADRATIC_TETRA);
170 bem.associate(HEX8, VTK_HEXAHEDRON);
171 bem.associate(HEX20, VTK_QUADRATIC_HEXAHEDRON);
172 bem.associate(HEX27, VTK_BEZIER_HEXAHEDRON);
173 bem.associate(PRISM6, VTK_WEDGE);
174 bem.associate(PRISM15, VTK_QUADRATIC_WEDGE);
175 bem.associate(PRISM18, VTK_BEZIER_WEDGE);
176 bem.associate(PYRAMID5, VTK_PYRAMID);
177 bem.writing_map[TRI3SUBDIVISION] = VTK_TRIANGLE;
179#endif
180
181 return all_maps;
182}
183
184
185
186void VTKIO::read (const std::string & name)
187{
188 // This is a serial-only process for now;
189 // the Mesh should be read on processor 0 and
190 // broadcast later
191 libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
192
193 // Keep track of what kinds of elements this file contains
194 elems_of_dimension.clear();
195 elems_of_dimension.resize(4, false);
196
197 // Use a typedef, because these names are just crazy
198 typedef vtkSmartPointer<vtkXMLPUnstructuredGridReader> MyReader;
199 MyReader reader = MyReader::New();
200
201 // Pass the filename along to the reader
202 reader->SetFileName(name.c_str());
203
204 // Force reading
205 reader->Update();
206
207 // read in the grid
208 _vtk_grid = reader->GetOutput();
209
210 // Get a reference to the mesh
212
213 // Clear out any pre-existing data from the Mesh
214 mesh.clear();
215
216 // Try to preserve any libMesh ids and subdomain ids we find in the
217 // file. This will be null if there are none, e.g. if a non-libMesh
218 // program wrote this file.
219
220 vtkAbstractArray * abstract_elem_id =
221 _vtk_grid->GetCellData()->GetAbstractArray("libmesh_elem_id");
222 vtkAbstractArray * abstract_node_id =
223 _vtk_grid->GetPointData()->GetAbstractArray("libmesh_node_id");
224 vtkAbstractArray * abstract_subdomain_id =
225 _vtk_grid->GetCellData()->GetAbstractArray("subdomain_id");
226
227 // Get ids as integers. This will be null if they are another data
228 // type, e.g. if a non-libMesh program used the names we thought
229 // were unique for different data.
230 vtkIntArray * elem_id = vtkIntArray::SafeDownCast(abstract_elem_id);
231 vtkIntArray * node_id = vtkIntArray::SafeDownCast(abstract_node_id);
232 vtkIntArray * subdomain_id = vtkIntArray::SafeDownCast(abstract_subdomain_id);
233
234 if (abstract_elem_id && !elem_id)
235 libmesh_warning("Found non-integral libmesh_elem_id array; forced to ignore it.\n"
236 "This is technically valid but probably broken.");
237
238 if (abstract_node_id && !node_id)
239 libmesh_warning("Found non-integral libmesh_node_id array; forced to ignore it.\n"
240 "This is technically valid but probably broken.");
241
242 if (abstract_subdomain_id && !subdomain_id)
243 libmesh_warning("Found non-integral subdomain_id array; forced to ignore it.\n"
244 "This is technically valid but probably broken.");
245
246 // Get the number of points from the _vtk_grid object
247 const unsigned int vtk_num_points = static_cast<unsigned int>(_vtk_grid->GetNumberOfPoints());
248
249 // Map from VTK indexing to libMesh id if necessary
250 std::vector<dof_id_type> vtk_node_to_libmesh;
251 if (node_id)
252 vtk_node_to_libmesh.resize(vtk_num_points);
253
254 // always numbered nicely so we can loop like this
255 for (unsigned int i=0; i<vtk_num_points; ++i)
256 {
257 // add to the id map
258 // and add the actual point
259 double pnt[3];
260 _vtk_grid->GetPoint(static_cast<vtkIdType>(i), pnt);
261 Point xyz(pnt[0], pnt[1], pnt[2]);
262
263 if (node_id)
264 {
265 auto id = node_id->GetValue(i);
266
267 // It would nice to distinguish between "duplicate nodes
268 // because one was ghosted in a parallel file segment" and
269 // "duplicate nodes because there was a bug", but I'm not
270 // sure how to do that with vtkXMLPUnstructuredGridReader
271 if (!mesh.query_node_ptr(id))
272 mesh.add_point(xyz, id);
273 vtk_node_to_libmesh[i] = id;
274 }
275 else
276 mesh.add_point(xyz, i);
277 }
278
279 // Get the number of cells from the _vtk_grid object
280 const unsigned int vtk_num_cells = static_cast<unsigned int>(_vtk_grid->GetNumberOfCells());
281
282 auto& element_map = libmesh_map_find(_element_maps, mesh.default_mapping_type());
283
284 vtkSmartPointer<vtkGenericCell> cell = vtkSmartPointer<vtkGenericCell>::New();
285 for (unsigned int i=0; i<vtk_num_cells; ++i)
286 {
287 _vtk_grid->GetCell(i, cell);
288
289 // Get the libMesh element type corresponding to this VTK element type.
290 ElemType libmesh_elem_type = element_map.find(cell->GetCellType());
291 auto elem = Elem::build(libmesh_elem_type);
292
293 // get the straightforward numbering from the VTK cells
294 for (auto j : elem->node_index_range())
295 {
296 const auto vtk_point_id = cell->GetPointId(j);
297 const dof_id_type libmesh_node_id = node_id ?
298 vtk_node_to_libmesh[vtk_point_id] : vtk_point_id;
299
300 elem->set_node(j, mesh.node_ptr(libmesh_node_id));
301 }
302
303 // then get the connectivity
304 std::vector<dof_id_type> conn;
305 elem->connectivity(0, VTK, conn);
306
307 // then reshuffle the nodes according to the connectivity, this
308 // two-time-assign would evade the definition of the vtk_mapping
309 for (unsigned int j=0,
310 n_conn = cast_int<unsigned int>(conn.size());
311 j != n_conn; ++j)
312 elem->set_node(j, mesh.node_ptr(conn[j]));
313
314 if (elem_id)
315 {
316 auto id = elem_id->GetValue(i);
317 libmesh_error_msg_if
318 (mesh.query_elem_ptr(id), "Duplicate element id " << id <<
319 " found in libmesh_elem_ids");
320 elem->set_id(id);
321 }
322 else
323 elem->set_id(i);
324
325 if (subdomain_id)
326 {
327 auto sbdid = subdomain_id->GetValue(i);
328 elem->subdomain_id() = sbdid;
329 }
330
331 elems_of_dimension[elem->dim()] = true;
332
333 mesh.add_elem(std::move(elem));
334 } // end loop over VTK cells
335
336 // Set the mesh dimension to the largest encountered for an element
337 for (unsigned char i=0; i!=4; ++i)
338 if (elems_of_dimension[i])
340
341#if LIBMESH_DIM < 3
342 libmesh_error_msg_if(mesh.mesh_dimension() > LIBMESH_DIM,
343 "Cannot open dimension "
345 << " mesh file when configured without "
347 << "D support.");
348#endif // LIBMESH_DIM < 3
349}
350
351
352
353void VTKIO::write_nodal_data (const std::string & fname,
354 const std::vector<Number> & soln,
355 const std::vector<std::string> & names)
356{
357 // Warn that the .pvtu file extension should be used. Paraview
358 // recognizes this, and it works in both serial and parallel. Only
359 // warn about this once.
360 if (!Utility::ends_with(fname, ".pvtu"))
361 libmesh_do_once(libMesh::err << "The .pvtu extension should be used when writing VTK files in libMesh.");
362
363 // If there are variable names being written, the solution vector
364 // should not be empty, it should have been broadcast to all
365 // processors by the MeshOutput base class, since VTK is a parallel
366 // format. Verify this before going further.
367 libmesh_error_msg_if(!names.empty() && soln.empty(),
368 "Empty soln vector in VTKIO::write_nodal_data().");
369
370 // Get a reference to the mesh
372
373 // we only use Unstructured grids
374 _vtk_grid = vtkSmartPointer<vtkUnstructuredGrid>::New();
375 vtkSmartPointer<vtkXMLPUnstructuredGridWriter> writer = vtkSmartPointer<vtkXMLPUnstructuredGridWriter>::New();
376#ifdef LIBMESH_HAVE_MPI
377 // Set VTK to the same communicator as libMesh
378 vtkSmartPointer<vtkMPICommunicator> vtk_comm = vtkSmartPointer<vtkMPICommunicator>::New();
379 MPI_Comm mpi_comm = mesh.comm().get();
380 vtkMPICommunicatorOpaqueComm vtk_opaque_comm(&mpi_comm);
381 vtk_comm->InitializeExternal(&vtk_opaque_comm);
382
383 vtkSmartPointer<vtkMPIController> vtk_mpi_ctrl = vtkSmartPointer<vtkMPIController>::New();
384 vtk_mpi_ctrl->SetCommunicator(vtk_comm);
385
386 writer->SetController(vtk_mpi_ctrl);
387#endif
388
389 // add nodes to the grid and update _local_node_map
390 _local_node_map.clear();
391 this->nodes_to_vtk();
392
393 // add cells to the grid
394 this->cells_to_vtk();
395
396 // add nodal solutions to the grid, if solutions are given
397 if (names.size() > 0)
398 {
399 std::size_t num_vars = names.size();
400 std::vector<Number> local_values;
401
402#ifdef LIBMESH_USE_COMPLEX_NUMBERS
403 std::vector<Real> local_real_values;
404#endif
405
406 for (std::size_t variable=0; variable<num_vars; ++variable)
407 {
408 get_local_node_values(local_values, variable, soln, names);
409
410#ifdef LIBMESH_USE_COMPLEX_NUMBERS
411 // write real part
412 local_real_values.resize(local_values.size());
413 std::transform(local_values.begin(), local_values.end(),
414 local_real_values.begin(),
415 [](Number x) { return x.real(); });
416 node_values_to_vtk(names[variable] + "_real", local_real_values);
417
418 // write imaginary part
419 local_real_values.resize(local_values.size());
420 std::transform(local_values.begin(), local_values.end(),
421 local_real_values.begin(),
422 [](Number x) { return x.imag(); });
423 node_values_to_vtk(names[variable] + "_imag", local_real_values);
424#else
425 node_values_to_vtk(names[variable], local_values);
426#endif
427 }
428 }
429
430 // Tell the writer how many partitions exist and on which processor
431 // we are currently
432 writer->SetNumberOfPieces(mesh.n_processors());
433 writer->SetStartPiece(mesh.processor_id());
434 writer->SetEndPiece(mesh.processor_id());
435
436 // partitions overlap by one node
437 // FIXME: According to this document
438 // http://paraview.org/Wiki/images/5/51/SC07_tut107_ParaView_Handouts.pdf
439 // the ghosts are cells rather than nodes.
440 writer->SetGhostLevel(1);
441
442 // VTK 6 replaces SetInput() with SetInputData(). See
443 // http://www.vtk.org/Wiki/VTK/VTK_6_Migration/Replacement_of_SetInput
444 // for the full explanation.
445#if VTK_VERSION_LESS_THAN(6,0,0)
446 writer->SetInput(_vtk_grid);
447#else
448 writer->SetInputData(_vtk_grid);
449#endif
450
451 writer->SetFileName(fname.c_str());
452 writer->SetDataModeToAscii();
453
454 // compress the output, if desired (switches also to binary)
455 if (this->_compress)
456 {
457#if !VTK_VERSION_LESS_THAN(5,6,0)
458 writer->SetCompressorTypeToZLib();
459 writer->SetDataModeToBinary();
460#else
461 libmesh_do_once(libMesh::err << "Compression not implemented with old VTK libs!" << std::endl;);
462#endif
463 }
464
465 writer->Write();
466
467}
468
469
470
471vtkUnstructuredGrid * VTKIO::get_vtk_grid()
472{
473 return _vtk_grid;
474}
475
476
477
479{
480 this->_compress = b;
481}
482
483
484
486{
488
489 // containers for points and coordinates of points
490 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
491 vtkSmartPointer<vtkDoubleArray> pcoords = vtkSmartPointer<vtkDoubleArray>::New();
492 // if this grid is to be used in VTK then the dimension of the points should be 3
493 pcoords->SetNumberOfComponents(LIBMESH_DIM);
494 pcoords->Allocate(3*mesh.n_local_nodes());
495 points->SetNumberOfPoints(mesh.n_local_nodes()); // it seems that it needs this to prevent a segfault
496
497 // SetRationalWeights() was introduced in VTK 9.0
498#if !VTK_VERSION_LESS_THAN(9,0,0)
499 bool have_weights = false;
500 int weight_index = 0;
501 vtkSmartPointer<vtkDoubleArray> rational_weights;
502
504 {
505 rational_weights = vtkSmartPointer<vtkDoubleArray>::New();
506 rational_weights->SetName("RationalWeights");
507 rational_weights->SetNumberOfComponents(1);
508 weight_index = static_cast<int>(mesh.default_mapping_data());
509 have_weights = true;
510 }
511#endif
512
513 vtkSmartPointer<vtkIntArray> node_id = vtkSmartPointer<vtkIntArray>::New();
514 node_id->SetName("libmesh_node_id");
515 node_id->SetNumberOfComponents(1);
516
517 unsigned int local_node_counter = 0;
518
519 for (const auto & node_ptr : mesh.local_node_ptr_range())
520 {
521 const Node & node = *node_ptr;
522
523 double pnt[3] = {0, 0, 0};
524 for (unsigned int i=0; i<LIBMESH_DIM; ++i)
525 pnt[i] = double(node(i));
526
527 // Fill mapping between global and local node numbers
528 _local_node_map[node.id()] = local_node_counter;
529
530 // add point
531#if VTK_VERSION_LESS_THAN(7,1,0)
532 pcoords->InsertNextTupleValue(pnt);
533#else
534 pcoords->InsertNextTuple(pnt);
535#endif
536#if !VTK_VERSION_LESS_THAN(9,0,0)
537 if (have_weights)
538 {
539 Real weight = node.get_extra_datum<Real>(weight_index);
540 rational_weights->InsertTuple1(local_node_counter, double(weight));
541 }
542#endif
543
544 node_id->InsertTuple1(local_node_counter, node.id());
545
546 ++local_node_counter;
547 }
548
549 // add coordinates to points
550 points->SetData(pcoords);
551
552 // add points to grid
553 _vtk_grid->SetPoints(points);
554 _vtk_grid->GetPointData()->AddArray(node_id);
555
556#if !VTK_VERSION_LESS_THAN(9,0,0)
557 if (have_weights)
558 _vtk_grid->GetPointData()->SetRationalWeights(rational_weights);
559
560#endif
561}
562
563
564
566{
568
569 auto& element_map = libmesh_map_find(_element_maps, mesh.default_mapping_type());
570 vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
571 vtkSmartPointer<vtkIdList> pts = vtkSmartPointer<vtkIdList>::New();
572
573 std::vector<int> types(mesh.n_active_local_elem());
574
575 // We already created this but we need to add more if we have any
576 // ghost nodes
577 vtkAbstractArray * abstract_node_id =
578 _vtk_grid->GetPointData()->GetAbstractArray("libmesh_node_id");
579 vtkIntArray * node_id = vtkIntArray::SafeDownCast(abstract_node_id);
580 libmesh_assert(node_id);
581
582 vtkSmartPointer<vtkIntArray> elem_id = vtkSmartPointer<vtkIntArray>::New();
583 elem_id->SetName("libmesh_elem_id");
584 elem_id->SetNumberOfComponents(1);
585
586 vtkSmartPointer<vtkIntArray> subdomain_id = vtkSmartPointer<vtkIntArray>::New();
587 subdomain_id->SetName("subdomain_id");
588 subdomain_id->SetNumberOfComponents(1);
589
590 vtkSmartPointer<vtkIntArray> elem_proc_id = vtkSmartPointer<vtkIntArray>::New();
591 elem_proc_id->SetName("processor_id");
592 elem_proc_id->SetNumberOfComponents(1);
593
594 unsigned active_element_counter = 0;
595 for (const auto & elem : mesh.active_local_element_ptr_range())
596 {
597 // When using rational bernstein these hold the weights
598 if ( elem->type() == NODEELEM )
599 continue;
600
601 pts->SetNumberOfIds(elem->n_nodes());
602
603 // get the connectivity for this element
604 std::vector<dof_id_type> conn;
605 elem->connectivity(0, VTK, conn);
606
607 for (unsigned int i=0,
608 n_conn = cast_int<unsigned int>(conn.size());
609 i != n_conn; ++i)
610 {
611 // If the node ID is not found in the _local_node_map, we'll
612 // add it to the _vtk_grid. NOTE[JWP]: none of the examples
613 // I have actually enters this section of code...
614 if (!_local_node_map.count(conn[i]))
615 {
616 dof_id_type global_node_id = elem->node_id(i);
617
618 const Point & the_node = mesh.point(global_node_id);
619
620 // InsertNextPoint accepts either a double or float array of length 3.
621 double pt[3] = {0., 0., 0.};
622 for (unsigned int d=0; d<LIBMESH_DIM; ++d)
623 pt[d] = double(the_node(d));
624
625 // Insert the point into the _vtk_grid
626 vtkIdType local = _vtk_grid->GetPoints()->InsertNextPoint(pt);
627
628 // Update the _local_node_map with the ID returned by VTK
629 _local_node_map[global_node_id] =
630 cast_int<dof_id_type>(local);
631
632 node_id->InsertTuple1(local, global_node_id);
633 }
634
635 // Otherwise, the node ID was found in the _local_node_map, so
636 // insert it into the vtkIdList.
637 pts->InsertId(i, _local_node_map[conn[i]]);
638 }
639
640 vtkIdType vtkcellid = cells->InsertNextCell(pts);
641 types[active_element_counter] = cast_int<int>(element_map.find(elem->type()));
642
643 elem_id->InsertTuple1(vtkcellid, elem->id());
644 subdomain_id->InsertTuple1(vtkcellid, elem->subdomain_id());
645 elem_proc_id->InsertTuple1(vtkcellid, elem->processor_id());
646 ++active_element_counter;
647 } // end loop over active elements
648
649 _vtk_grid->SetCells(types.data(), cells);
650 _vtk_grid->GetCellData()->AddArray(elem_id);
651 _vtk_grid->GetCellData()->AddArray(subdomain_id);
652 _vtk_grid->GetCellData()->AddArray(elem_proc_id);
653}
654
655void VTKIO::node_values_to_vtk(const std::string & name,
656 const std::vector<Real> & local_values)
657{
658 vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
659 data->SetName(name.c_str());
660
661 libmesh_assert_equal_to(_local_node_map.size(), local_values.size());
662
663 // number of local and ghost nodes
664 data->SetNumberOfValues(_local_node_map.size());
665
666 // copy values into vtk
667 for (auto i : index_range(local_values)) {
668 data->SetValue(i, double(local_values[i]));
669 }
670
671 _vtk_grid->GetPointData()->AddArray(data);
672}
673
674void VTKIO::get_local_node_values(std::vector<Number> & local_values,
675 std::size_t variable,
676 const std::vector<Number> & soln,
677 const std::vector<std::string> & names)
678{
680 std::size_t num_vars = names.size();
681 dof_id_type num_nodes = mesh.n_nodes();
682
683 local_values.clear();
684 local_values.resize(_local_node_map.size(), 0.0);
685
686 // loop over all nodes and get the solution for the current
687 // variable, if the node is in the current partition
688 for (dof_id_type k=0; k<num_nodes; ++k)
689 if (const auto local_node_it = _local_node_map.find(k);
690 local_node_it != _local_node_map.end())
691 local_values[local_node_it->second] = soln[k*num_vars + variable];
692}
693
694
695
703// void VTKIO::system_vectors_to_vtk(const EquationSystems & es,
704// vtkUnstructuredGrid *& grid)
705// {
706// if (MeshOutput<MeshBase>::mesh().processor_id() == 0)
707// {
708// std::map<std::string, std::vector<Number>> vecs;
709// for (unsigned int i=0; i<es.n_systems(); ++i)
710// {
711// const System & sys = es.get_system(i);
712// System::const_vectors_iterator v_end = sys.vectors_end();
713// System::const_vectors_iterator it = sys.vectors_begin();
714// for (; it!= v_end; ++it)
715// {
716// // for all vectors on this system
717// std::vector<Number> values;
718// // libMesh::out<<"it "<<it->first<<std::endl;
719//
720// it->second->localize_to_one(values, 0);
721// // libMesh::out<<"finish localize"<<std::endl;
722// vecs[it->first] = values;
723// }
724// }
725//
726// std::map<std::string, std::vector<Number>>::iterator it = vecs.begin();
727//
728// for (; it!=vecs.end(); ++it)
729// {
730// vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
731// data->SetName(it->first.c_str());
732// libmesh_assert_equal_to (it->second.size(), es.get_mesh().n_nodes());
733// data->SetNumberOfValues(it->second.size());
734//
735// for (auto i : index_range(it->second))
736// {
737// #ifdef LIBMESH_USE_COMPLEX_NUMBERS
738// libmesh_do_once (libMesh::err << "Only writing the real part for complex numbers!\n"
739// << "if you need this support contact " << LIBMESH_PACKAGE_BUGREPORT
740// << std::endl);
741// data->SetValue(i, it->second[i].real());
742// #else
743// data->SetValue(i, it->second[i]);
744// #endif
745//
746// }
747// grid->GetPointData()->AddArray(data);
748// }
749// }
750// }
751
752
753
754#else // !LIBMESH_HAVE_VTK
755
756void VTKIO::read (const std::string & name)
757{
758 libmesh_error_msg("Cannot read VTK file: " << name \
759 << "\nYou must have VTK installed and correctly configured to read VTK meshes.");
760}
761
762
763
764void VTKIO::write_nodal_data (const std::string & fname,
765 const std::vector<Number> &,
766 const std::vector<std::string> &)
767{
768 libmesh_error_msg("Cannot write VTK file: " << fname \
769 << "\nYou must have VTK installed and correctly configured to read VTK meshes.");
770}
771
772
773#endif // LIBMESH_HAVE_VTK
774
775
776
777} // namespace libMesh
T get_extra_datum(const unsigned int index) const
Gets the value on this object of the extra datum associated with index, which should have been obtain...
dof_id_type id() const
Definition dof_object.h:819
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:442
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
virtual dof_id_type n_nodes() const =0
ElemMappingType default_mapping_type() const
Returns the default master space to physical space mapping basis functions to be used on newly added ...
Definition mesh_base.h:941
virtual const Node * query_node_ptr(const dof_id_type i) const =0
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition mesh_base.h:423
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition mesh_base.C:1036
dof_id_type n_local_nodes() const
Definition mesh_base.h:591
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
dof_id_type n_active_local_elem() const
Definition mesh_base.h:714
unsigned char default_mapping_data() const
Returns any default data value used by the master space to physical space mapping.
Definition mesh_base.h:959
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
const MT & mesh() const
A Node is like a Point, but with more information.
Definition node.h:55
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
void node_values_to_vtk(const std::string &name, const std::vector< Real > &local_values)
write the nodal values of soln to a vtkUnstructuredGrid
Definition vtk_io.C:655
void nodes_to_vtk()
write the nodes from the mesh into a vtkUnstructuredGrid and update the local_node_map.
Definition vtk_io.C:485
std::map< dof_id_type, dof_id_type > _local_node_map
maps global node id to node id of partition
Definition vtk_io.h:179
virtual void write(const std::string &) override
Output the mesh without solutions to a .pvtu file.
static std::map< ElemMappingType, ElementMaps > _element_maps
ElementMaps objects that are built statically and used by all instances of this class.
Definition vtk_io.h:215
VTKIO(MeshBase &mesh)
Constructor.
Definition vtk_io.C:83
bool _compress
Flag to indicate whether the output should be compressed.
Definition vtk_io.h:174
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 vtk_io.C:353
virtual void read(const std::string &) override
This method implements reading a mesh from a specified file in VTK format.
Definition vtk_io.C:186
void cells_to_vtk()
write the cells from the mesh into a vtkUnstructuredGrid
Definition vtk_io.C:565
void set_compression(bool b)
Setter for compression flag.
Definition vtk_io.C:478
void get_local_node_values(std::vector< Number > &local_values, std::size_t variable, const std::vector< Number > &soln, const std::vector< std::string > &names)
Extract the values of soln that correspond to the nodes.
Definition vtk_io.C:674
vtkUnstructuredGrid * get_vtk_grid()
Get a pointer to the VTK unstructured grid data structure.
Definition vtk_io.C:471
static std::map< ElemMappingType, ElementMaps > build_element_maps()
Static function used to construct _element_maps.
Definition vtk_io.C:123
vtkSmartPointer< vtkUnstructuredGrid > _vtk_grid
Write the system vectors to vtk.
Definition vtk_io.h:169
static const Real b
MeshBase & mesh
bool ends_with(std::string_view superstring, std::string_view suffix)
Look for a substring at the very end of a string.
Definition utility.C:213
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.
@ RATIONAL_BERNSTEIN_MAP
libmesh_assert(ctx)
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Helper object that holds a map from VTK to libMesh element types and vice-versa.
Definition vtk_io.h:187
std::map< ElemType, vtkIdType > writing_map
Definition vtk_io.h:207
void associate(ElemType libmesh_type, vtkIdType vtk_type)
Definition vtk_io.h:189