LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
vtk_writer.h
1
10#ifndef __3e48c7b32a034cb3be3dbca884ff4f6c
11#define __3e48c7b32a034cb3be3dbca884ff4f6c
12
13#include <lf/mesh/mesh.h>
14#include <lf/mesh/utils/utils.h>
15
16#include <boost/variant/variant.hpp>
17#include <string>
18#include <utility>
19#include <vector>
20
21namespace lf::io {
22
31class VtkFile {
32 public:
33 using size_type = unsigned int;
34
37 enum class Format { ASCII, BINARY };
38
39 enum class CellType {
40 VTK_VERTEX = 1,
41 VTK_POLY_VERTEX = 2,
42 VTK_LINE = 3,
43 VTK_POLY_LINE = 4,
44 VTK_TRIANGLE = 5,
45 VTK_TRIANGLE_STRIP = 6,
46 VTK_POLYGON = 7,
47 VTK_PIXEL = 8,
48 VTK_QUAD = 9,
49 VTK_TETRA = 10,
50 VTK_VOXEL = 11,
51 VTK_HEXAHEDRON = 12,
52 VTK_WEDGE = 13,
53 VTK_PYRAMID = 14,
54 VTK_QUADRATIC_EDGE = 21,
55 VTK_QUADRATIC_TRIANGLE = 22,
56 VTK_QUADRATIC_QUAD = 23,
57 VTK_QUADRATIC_TETRA = 24,
58 VTK_QUADRATIC_HEXAHEDRON = 25,
59 VTK_LAGRANGE_CURVE = 68,
60 VTK_LAGRANGE_TRIANGLE = 69,
61 VTK_LAGRANGE_QUADRILATERAL = 70,
62 VTK_LAGRANGE_TETRAHEDRON = 71,
63 VTK_LAGRANGE_HEXAHEDRON = 72,
64 VTK_LAGRANGE_WEDGE = 73,
65 VTK_LAGRANGE_PYRAMID = 74
66 };
67
69 public:
70 std::vector<Eigen::Vector3f> points;
71 std::vector<std::vector<size_type>> cells;
72 std::vector<CellType> cell_types;
73 };
74
75 template <class T>
77 public:
78 std::string name;
79 std::vector<T> data;
80
81 FieldDataArray() = default;
82
83 explicit FieldDataArray(std::string name, std::vector<T> data)
84 : name(std::move(name)), data(std::move(data)) {}
85 };
86
88 template <class T>
89 class ScalarData {
90 public:
91 std::string name;
92 std::vector<T> data;
93 std::string lookup_table = "default";
94
95 ScalarData() = default;
96
97 explicit ScalarData(std::string data_name, std::vector<T> data,
98 std::string lookup_table = "default")
99 : name(std::move(data_name)),
100 data(std::move(data)),
101 lookup_table(std::move(lookup_table)) {}
102 };
103
104 template <class T>
106 public:
107 std::string name;
108 std::vector<Eigen::Matrix<T, 3, 1>> data;
109
110 VectorData() = default;
111
112 explicit VectorData(std::string name,
113 std::vector<Eigen::Matrix<T, 3, 1>> data)
114 : name(std::move(name)), data(std::move(data)) {}
115 };
116
117 // WARNING: the type long is interepreted differently depending on the
118 // platorm. I suggest to not use it at all.
119 using Attributes = std::vector<boost::variant<
124
125 using FieldData =
126 std::vector<boost::variant<FieldDataArray<int>, FieldDataArray<float>,
128
129 // Actual members
131
133 std::string header;
136
139
141
142 // Data that is attached to points
144
145 // Data that is attached to the cells of the mesh
147};
148
149void WriteToFile(const VtkFile& vtk_file, const std::string& filename);
150
151// clang-format off
152
271// clang-format on
273 public:
275
276 VtkWriter(const VtkWriter&) = delete;
277 VtkWriter(VtkWriter&&) = delete;
278 VtkWriter& operator=(const VtkWriter&) = delete;
280
295 VtkWriter(std::shared_ptr<const mesh::Mesh> mesh, std::string filename,
296 dim_t codim = 0, unsigned char order = 1);
297
303 void setBinary(bool binary) {
304 if (binary) {
306 } else {
308 }
309 }
310
323 void WritePointData(const std::string& name,
325 unsigned char undefined_value = 0);
326
339 void WritePointData(const std::string& name,
341 char undefined_value = 0);
342
355 void WritePointData(const std::string& name,
357 unsigned int undefined_value = 0);
358
371 void WritePointData(const std::string& name,
373 int undefined_value = 0);
374
387 void WritePointData(const std::string& name,
389 float undefined_value = 0.F);
390
403 void WritePointData(const std::string& name,
405 double undefined_value = 0.);
406
419 void WritePointData(const std::string& name,
421 const Eigen::Vector2d& undefined_value = {0, 0});
422
435 void WritePointData(const std::string& name,
437 const Eigen::Vector2f& undefined_value = {0, 0});
438
451 void WritePointData(const std::string& name,
452 const mesh::utils::MeshDataSet<Eigen::Vector3d>& mds,
453 const Eigen::Vector3d& undefined_value = {0, 0, 0});
454
467 void WritePointData(const std::string& name,
468 const mesh::utils::MeshDataSet<Eigen::Vector3f>& mds,
469 const Eigen::Vector3f& undefined_value = {0, 0, 0});
470
485 void WritePointData(
486 const std::string& name,
487 const mesh::utils::MeshDataSet<Eigen::VectorXd>& mds,
488 const Eigen::VectorXd& undefined_value = Eigen::Vector3d(0, 0, 0));
489
504 void WritePointData(
505 const std::string& name,
506 const mesh::utils::MeshDataSet<Eigen::VectorXf>& mds,
507 const Eigen::VectorXf& undefined_value = Eigen::Vector3f(0, 0, 0));
508
541 template <
542 class MESH_FUNCTION,
543 class = std::enable_if_t<lf::mesh::utils::isMeshFunction<MESH_FUNCTION>>>
544 void WritePointData(const std::string& name,
545 const MESH_FUNCTION& mesh_function);
546
557 void WriteCellData(const std::string& name,
558 const mesh::utils::MeshDataSet<unsigned char>& mds,
559 unsigned char undefined_value = 0);
560
571 void WriteCellData(const std::string& name,
572 const mesh::utils::MeshDataSet<char>& mds,
573 char undefined_value = 0);
574
585 void WriteCellData(const std::string& name,
586 const mesh::utils::MeshDataSet<unsigned int>& mds,
587 unsigned int undefined_value = 0);
588
599 void WriteCellData(const std::string& name,
600 const mesh::utils::MeshDataSet<int>& mds,
601 int undefined_value = 0);
602
613 void WriteCellData(const std::string& name,
614 const mesh::utils::MeshDataSet<float>& mds,
615 float undefined_value = 0);
616
627 void WriteCellData(const std::string& name,
628 const mesh::utils::MeshDataSet<double>& mds,
629 double undefined_value = 0);
630
640 void WriteCellData(const std::string& name,
641 const mesh::utils::MeshDataSet<Eigen::Vector2d>& mds,
642 const Eigen::Vector2d& undefined_value = {0, 0});
643
653 void WriteCellData(const std::string& name,
654 const mesh::utils::MeshDataSet<Eigen::Vector2f>& mds,
655 const Eigen::Vector2f& undefined_value = {0, 0});
656
666 void WriteCellData(const std::string& name,
667 const mesh::utils::MeshDataSet<Eigen::Vector3d>& mds,
668 const Eigen::Vector3d& undefined_value = {0, 0, 0});
669
679 void WriteCellData(const std::string& name,
680 const mesh::utils::MeshDataSet<Eigen::Vector3f>& mds,
681 const Eigen::Vector3f& undefined_value = {0, 0, 0});
682
694 void WriteCellData(
695 const std::string& name,
696 const mesh::utils::MeshDataSet<Eigen::VectorXd>& mds,
697 const Eigen::VectorXd& undefined_value = Eigen::Vector3d(0, 0, 0));
698
710 void WriteCellData(
711 const std::string& name,
712 const mesh::utils::MeshDataSet<Eigen::VectorXf>& mds,
713 const Eigen::VectorXf& undefined_value = Eigen::Vector3f(0, 0, 0));
714
743 template <
744 class MESH_FUNCTION,
745 class = std::enable_if_t<lf::mesh::utils::isMeshFunction<MESH_FUNCTION>>>
746 void WriteCellData(const std::string& name,
747 const MESH_FUNCTION& mesh_function);
748
759 void WriteGlobalData(const std::string& name, std::vector<int> data);
760
771 void WriteGlobalData(const std::string& name, std::vector<float> data);
772
783 void WriteGlobalData(const std::string& name, std::vector<double> data);
784
789
790 private:
791 std::shared_ptr<const mesh::Mesh> mesh_;
793 std::string filename_;
795 unsigned char order_;
796
797 // entry [i] stores the reference coordinates for the auxilliary nodes for
798 // RefEl.Id() == i
799 std::array<Eigen::MatrixXd, 5> aux_nodes_;
800
801 // entry[cd] contains the index of the first auxiliary node for the codim=cd
802 // entity
803 std::array<mesh::utils::CodimMeshDataSet<unsigned int>, 2> aux_node_offset_;
804
805 template <class T>
806 void WriteScalarPointData(const std::string& name,
808 T undefined_value);
809
810 template <int ROWS, class T>
812 const std::string& name,
813 const mesh::utils::MeshDataSet<Eigen::Matrix<T, ROWS, 1>>& mds,
814 const Eigen::Matrix<T, ROWS, 1>& undefined_value);
815
816 template <class T>
817 void WriteScalarCellData(const std::string& name,
819 T undefined_value);
820
821 template <int ROWS, class T>
823 const std::string& name,
824 const mesh::utils::MeshDataSet<Eigen::Matrix<T, ROWS, 1>>& mds,
825 const Eigen::Matrix<T, ROWS, 1>& undefined_value);
826
827 template <class T>
828 void WriteFieldData(const std::string& name, std::vector<T> data);
829
830 template <class DATA>
831 void CheckAttributeSetName(const DATA& data, const std::string& name);
832
833 template <int ROWS, class T>
834 static void PadWithZeros(Eigen::Matrix<T, 3, 1>& out,
835 const Eigen::Matrix<T, ROWS, 1>& in);
836};
837
838template <class MESH_FUNCTION, class>
839void VtkWriter::WritePointData(const std::string& name,
840 const MESH_FUNCTION& mesh_function) {
841 // we have to evaluate the mesh function at all points
842 // and write this into the vtk file:
845 auto dim_mesh = mesh_->DimMesh();
846
847 Eigen::Matrix<double, 0, 1> origin;
848
849 if constexpr (std::is_same_v<T, unsigned char> || std::is_same_v<T, char> ||
850 std::is_same_v<T, unsigned> || std::is_same_v<T, int> ||
851 std::is_same_v<T, float> ||
852 std::is_same_v<T, double>) { // NOLINT
853 // MeshFunction is scalar valued:
855 data.data.resize(vtk_file_.unstructured_grid.points.size());
856 data.name = name;
857
858 // evaluate at nodes:
859 for (const auto* n : mesh_->Entities(dim_mesh)) {
860 data.data[mesh_->Index(*n)] = mesh_function(*n, origin)[0];
861 }
862
863 for (int codim = static_cast<int>(dim_mesh - 1);
864 codim >= static_cast<char>(codim_); --codim) {
865 for (const auto* e : mesh_->Entities(codim)) {
866 auto ref_el = e->RefEl();
867 if (order_ == 1 || (order_ == 2 && ref_el == base::RefEl::kTria())) {
868 continue;
869 }
870 auto values = mesh_function(*e, aux_nodes_[ref_el.Id()]);
871 auto offset = aux_node_offset_[codim](*e);
872 for (typename std::vector<T>::size_type i = 0; i < values.size(); ++i) {
873 data.data[offset + i] = values[i];
874 }
875 }
876 }
877 vtk_file_.point_data.push_back(std::move(data));
878 } else if constexpr (base::is_eigen_matrix<T>) { // NOLINT
879 static_assert(T::ColsAtCompileTime == 1,
880 "The MeshFunction must return row-vectors");
881 static_assert(
882 T::RowsAtCompileTime == Eigen::Dynamic ||
883 (T::RowsAtCompileTime > 1 && T::RowsAtCompileTime < 4),
884 "The Row vectors returned by the MeshFunction must be either dynamic "
885 "or must have 2 or 3 rows (at compile time).");
886 using Scalar = typename T::Scalar;
887 static_assert(
888 std::is_same_v<double, Scalar> || std::is_same_v<float, Scalar>,
889 "The RowVectors returned by the MeshFunction must be either double "
890 "or float valued.");
892 data.data.resize(vtk_file_.unstructured_grid.points.size());
893 data.name = name;
894
895 // evaluate at nodes:
896 for (const auto* n : mesh_->Entities(dim_mesh)) {
897 PadWithZeros<T::RowsAtCompileTime, Scalar>(data.data[mesh_->Index(*n)],
898 mesh_function(*n, origin)[0]);
899 }
900
901 for (int codim = static_cast<int>(dim_mesh - 1);
902 codim >= static_cast<char>(codim_); --codim) {
903 for (const auto* e : mesh_->Entities(codim)) {
904 auto ref_el = e->RefEl();
905 if (order_ < 2 || (order_ < 3 && ref_el == base::RefEl::kTria())) {
906 continue;
907 }
908 auto values = mesh_function(*e, aux_nodes_[ref_el.Id()]);
909 auto offset = aux_node_offset_[codim](*e);
910 for (unsigned long i = 0; i < values.size(); ++i) {
911 PadWithZeros<T::RowsAtCompileTime, Scalar>(data.data[offset + i],
912 values[i]);
913 }
914 }
915 }
916 vtk_file_.point_data.push_back(std::move(data));
917 } else {
918 LF_VERIFY_MSG(false,
919 "MeshFunction values must be one of: unsigned char, char, "
920 "unsigned, int, float, double, Eigen::Vector<double, ...> "
921 "or Eigen::Vector<float, ...>");
922 }
923}
924
925template <class MESH_FUNCTION, class>
926void VtkWriter::WriteCellData(const std::string& name,
927 const MESH_FUNCTION& mesh_function) {
930
931 // maps from RefEl::Id() -> barycenter of the reference element
932 std::vector<Eigen::VectorXd> barycenters(5);
933 barycenters[base::RefEl::kPoint().Id()] = Eigen::Matrix<double, 0, 1>();
934 barycenters[base::RefEl::kSegment().Id()] =
935 base::RefEl::kSegment().NodeCoords().rowwise().sum() / 2.;
936 barycenters[base::RefEl::kTria().Id()] =
937 base::RefEl::kTria().NodeCoords().rowwise().sum() / 3.;
938 barycenters[base::RefEl::kQuad().Id()] =
939 base::RefEl::kTria().NodeCoords().rowwise().sum() / 4.;
940
941 if constexpr (base::is_eigen_array<T> || base::is_eigen_matrix<T>) {
942 static_assert(T::ColsAtCompileTime == 1,
943 "The MeshFunction must return row-vectors");
944 static_assert(
945 T::RowsAtCompileTime == Eigen::Dynamic ||
946 (T::RowsAtCompileTime > 1 && T::RowsAtCompileTime < 4),
947 "The Row vectors returned by the MeshFunction must be either dynamic "
948 "or must have 2 or 3 rows (at compile time).");
949 using Scalar = typename T::Scalar;
950 static_assert(
951 std::is_same_v<double, Scalar> || std::is_same_v<float, Scalar>,
952 "The RowVectors returned by the MeshFunction must be either double "
953 "or float valued.");
955 data.data.resize(mesh_->NumEntities(codim_));
956 data.name = name;
957 constexpr int rows = T::RowsAtCompileTime;
958 for (const auto* p : mesh_->Entities(codim_)) {
959 this->PadWithZeros<rows, Scalar>(
960 data.data[mesh_->Index(*p)],
961 mesh_function(*p, barycenters[p->RefEl().Id()])[0]);
962 }
963 vtk_file_.cell_data.push_back(std::move(data));
964 } else {
966 data.data.resize(mesh_->NumEntities(codim_));
967 data.name = name;
968 for (const auto* e : mesh_->Entities(codim_)) {
969 data.data[mesh_->Index(*e)] =
970 mesh_function(*e, barycenters[e->RefEl().Id()])[0];
971 }
972 vtk_file_.cell_data.push_back(std::move(data));
973 }
974}
975
976template <class DATA>
978 const std::string& name) {
979 if (std::find_if(data.begin(), data.end(), [&](auto& d) {
980 return boost::apply_visitor([&](auto&& d2) { return d2.name; }, d) ==
981 name;
982 }) != data.end()) {
983 throw base::LfException(
984 "There is already another Point/Cell Attribute Set with the "
985 "name " +
986 name);
987 }
988 if (name.find(' ') != std::string::npos) {
989 throw base::LfException(
990 "The name of the attribute set cannot contain spaces!");
991 }
992}
993
994template <int ROWS, class T>
995void VtkWriter::PadWithZeros(Eigen::Matrix<T, 3, 1>& out,
996 const Eigen::Matrix<T, ROWS, 1>& in) {
997 if constexpr (ROWS == 2) { // NOLINT
998 out.template block<2, 1>(0, 0) = in;
999 out(2) = T(0);
1000 } else if constexpr (ROWS == 3) { // NOLINT
1001 out = in;
1002 } else if constexpr (ROWS == Eigen::Dynamic) { // NOLINT
1003 LF_ASSERT_MSG(in.rows() == 2 || in.rows() == 3,
1004 "VtkWriter can only write out 2d or 3d vectors.");
1005 if (in.rows() == 2) {
1006 out(2) = T(0);
1007 out.topRows(2) = in;
1008 } else {
1009 out = in;
1010 }
1011 }
1012}
1013
1014} // namespace lf::io
1015
1016#endif // __3e48c7b32a034cb3be3dbca884ff4f6c
A simple, general purpose exception class that is thrown by LehrFEM++ if something is wrong.
Definition: lf_exception.h:21
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
Definition: ref_el.h:150
constexpr unsigned int Id() const
Return a unique id for this reference element.
Definition: ref_el.h:491
const Eigen::MatrixXd & NodeCoords() const
Get the coordinates of the nodes of this reference element.
Definition: ref_el.h:238
static constexpr RefEl kPoint()
Returns the (0-dimensional) reference point.
Definition: ref_el.h:141
static constexpr RefEl kTria()
Returns the reference triangle.
Definition: ref_el.h:158
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
Definition: ref_el.h:166
FieldDataArray(std::string name, std::vector< T > data)
Definition: vtk_writer.h:83
Represents one set of attribute data (can be attached to points or cells)
Definition: vtk_writer.h:89
std::vector< T > data
Definition: vtk_writer.h:92
ScalarData(std::string data_name, std::vector< T > data, std::string lookup_table="default")
Definition: vtk_writer.h:97
std::vector< Eigen::Vector3f > points
Definition: vtk_writer.h:70
std::vector< std::vector< size_type > > cells
Definition: vtk_writer.h:71
std::vector< CellType > cell_types
Definition: vtk_writer.h:72
VectorData(std::string name, std::vector< Eigen::Matrix< T, 3, 1 > > data)
Definition: vtk_writer.h:112
std::vector< Eigen::Matrix< T, 3, 1 > > data
Definition: vtk_writer.h:108
Representation of a VTK file (only relevant) features (advanced usage)
Definition: vtk_writer.h:31
FieldData field_data
Definition: vtk_writer.h:140
std::vector< boost::variant< FieldDataArray< int >, FieldDataArray< float >, FieldDataArray< double > > > FieldData
Definition: vtk_writer.h:127
std::string header
The Vtk Header, at most 256 characters, no new lines characters!
Definition: vtk_writer.h:133
UnstructuredGrid unstructured_grid
Describes the nodes + cells.
Definition: vtk_writer.h:138
Format
Nested types.
Definition: vtk_writer.h:37
std::vector< boost::variant< ScalarData< char >, ScalarData< unsigned char >, ScalarData< short >, ScalarData< unsigned short >, ScalarData< int >, ScalarData< unsigned int >, ScalarData< long >, ScalarData< unsigned long >, ScalarData< float >, ScalarData< double >, VectorData< float >, VectorData< double > > > Attributes
Definition: vtk_writer.h:123
Attributes cell_data
Definition: vtk_writer.h:146
Format format
The format of the file.
Definition: vtk_writer.h:135
unsigned int size_type
Definition: vtk_writer.h:33
Attributes point_data
Definition: vtk_writer.h:143
Write a mesh along with mesh data into a vtk file.
Definition: vtk_writer.h:272
void setBinary(bool binary)
Determines whether the Vtk file is written in binary or ASCII mode (default).
Definition: vtk_writer.h:303
VtkWriter(VtkWriter &&)=delete
void WriteScalarPointData(const std::string &name, const mesh::utils::MeshDataSet< T > &mds, T undefined_value)
Definition: vtk_writer.cc:954
VtkWriter(const VtkWriter &)=delete
base::dim_t dim_t
Definition: vtk_writer.h:274
void WriteCellData(const std::string &name, const mesh::utils::MeshDataSet< unsigned char > &mds, unsigned char undefined_value=0)
Add a new unsigned char attribute dataset that attaches data to the cells of the mesh (i....
Definition: vtk_writer.cc:860
~VtkWriter()
Destructor, writes everything into the file and closes it.
Definition: vtk_writer.h:788
void WriteScalarCellData(const std::string &name, const mesh::utils::MeshDataSet< T > &mds, T undefined_value)
Definition: vtk_writer.cc:1000
VtkWriter & operator=(VtkWriter &&)=delete
std::array< mesh::utils::CodimMeshDataSet< unsigned int >, 2 > aux_node_offset_
Definition: vtk_writer.h:803
static void PadWithZeros(Eigen::Matrix< T, 3, 1 > &out, const Eigen::Matrix< T, ROWS, 1 > &in)
Definition: vtk_writer.h:995
void WriteFieldData(const std::string &name, std::vector< T > data)
Definition: vtk_writer.cc:1040
VtkWriter & operator=(const VtkWriter &)=delete
void WriteGlobalData(const std::string &name, std::vector< int > data)
Write global data into the vtk file that is not related to the mesh at all.
Definition: vtk_writer.cc:938
void WriteVectorPointData(const std::string &name, const mesh::utils::MeshDataSet< Eigen::Matrix< T, ROWS, 1 > > &mds, const Eigen::Matrix< T, ROWS, 1 > &undefined_value)
Definition: vtk_writer.cc:975
void WriteVectorCellData(const std::string &name, const mesh::utils::MeshDataSet< Eigen::Matrix< T, ROWS, 1 > > &mds, const Eigen::Matrix< T, ROWS, 1 > &undefined_value)
Definition: vtk_writer.cc:1018
unsigned char order_
Definition: vtk_writer.h:795
void CheckAttributeSetName(const DATA &data, const std::string &name)
Definition: vtk_writer.h:977
std::string filename_
Definition: vtk_writer.h:793
std::shared_ptr< const mesh::Mesh > mesh_
Definition: vtk_writer.h:791
std::array< Eigen::MatrixXd, 5 > aux_nodes_
Definition: vtk_writer.h:799
void WritePointData(const std::string &name, const mesh::utils::MeshDataSet< unsigned char > &mds, unsigned char undefined_value=0)
Add a new unsigned char attribute dataset that attaches data to the points/nodes of the mesh.
Definition: vtk_writer.cc:782
Interface that specifies how data is stored with an entity.
Definition: mesh_data_set.h:36
unsigned int dim_t
type for dimensions and co-dimensions and numbers derived from them
Definition: base.h:36
unsigned int size_type
general type for variables related to size of arrays
Definition: base.h:24
Mesh input (from file) and output (in various formats) facilities.
Definition: gmsh_file_v2.cc:35
void WriteToFile(const VtkFile &vtk_file, const std::string &filename)
Definition: vtk_writer.cc:550
internal::VectorElement_t< internal::MeshFunctionReturnType_t< R > > MeshFunctionReturnType
Determine the type of objects returned by a MeshFunction.