Bembel
VTKSurfaceExport.hpp
1 // This file is part of Bembel, the higher order C++ boundary element library.
2 //
3 // Copyright (C) 2022 see <http://www.bembel.eu>
4 //
5 // It was written as part of a cooperation of J. Doelz, H. Harbrecht, S. Kurz,
6 // M. Multerer, S. Schoeps, and F. Wolf at Technische Universitaet Darmstadt,
7 // Universitaet Basel, and Universita della Svizzera italiana, Lugano. This
8 // source code is subject to the GNU General Public License version 3 and
9 // provided WITHOUT ANY WARRANTY, see <http://www.bembel.eu> for further
10 // information.
11 
12 #ifndef BEMBEL_SRC_IO_VTKSURFACEEXPORT_HPP_
13 #define BEMBEL_SRC_IO_VTKSURFACEEXPORT_HPP_
14 
15 namespace Bembel {
16 
25  public:
31  VTKSurfaceExport(const Geometry& geo, int M) {
32  init_VTKSurfaceExport(geo, M);
33  }
34  inline void init_VTKSurfaceExport(const Geometry& geo, int M) {
35  msh.init_ClusterTree(geo, M);
36  points = msh.get_element_tree().generatePointList().transpose();
37  cells = msh.get_element_tree().generateElementList().transpose();
38  normals = Eigen::MatrixXd(cells.rows(), 3);
39  patch_number = Eigen::VectorXi(cells.rows());
40 
41  for (auto e = msh.get_element_tree().cpbegin();
42  e != msh.get_element_tree().cpend(); ++e) {
43  normals.row(e->id_) = msh.get_geometry()[e->patch_]
44  .evalNormal(e->referenceMidpoint())
45  .normalized()
46  .transpose();
47  }
48  for (auto e = msh.get_element_tree().cpbegin();
49  e != msh.get_element_tree().cpend(); ++e) {
50  patch_number(e->id_) = e->patch_;
51  }
52  return;
53  }
57  inline void addDataSet(
58  const std::string& name,
59  std::function<double(int, const Eigen::Vector2d&)> fun) {
60  addDataSet_(name, getData_<double>(fun));
61  return;
62  }
66  inline void addDataSet(
67  const std::string& name,
68  std::function<std::complex<double>(int, const Eigen::Vector2d&)> fun) {
69  Eigen::VectorXcd data = getData_<std::complex<double>>(fun);
70  addDataSet_(name + std::string("_real"), data.real());
71  addDataSet_(name + std::string("_imag"), data.imag());
72  return;
73  }
77  inline void addDataSet(
78  const std::string& name,
79  std::function<Eigen::Vector3d(int, const Eigen::Vector2d&)> fun) {
80  addDataSet_(name, getData_<double, 3>(fun));
81  return;
82  }
86  inline void addDataSet(
87  const std::string& name,
88  std::function<Eigen::Vector3cd(int, const Eigen::Vector2d&)> fun) {
89  Eigen::MatrixXcd data = getData_<std::complex<double>, 3>(fun);
90  addDataSet_(name + std::string("_real"), data.real());
91  addDataSet_(name + std::string("_imag"), data.imag());
92  return;
93  }
97  inline void addDataSet(
98  const std::string& name,
99  std::function<Eigen::Vector3d(const Eigen::Vector3d&)> fun) {
100  addDataSet_(name, getData_<double, 3>(fun));
101  return;
102  }
106  inline void addDataSet(
107  const std::string& name,
108  std::function<Eigen::Vector3cd(const Eigen::Vector3d&)> fun) {
109  Eigen::MatrixXcd data = getData_<std::complex<double>, 3>(fun);
110  addDataSet_(name + std::string("_real"), data.real());
111  addDataSet_(name + std::string("_imag"), data.imag());
112  return;
113  }
117  inline void addDataSet(const std::string& name,
118  std::function<double(const Eigen::Vector3d&)> fun) {
119  addDataSet_(name, getData_<double>(fun));
120  return;
121  }
125  inline void addDataSet(
126  const std::string& name,
127  std::function<std::complex<double>(const Eigen::Vector3d&)> fun) {
128  Eigen::VectorXcd data = getData_<std::complex<double>>(fun);
129  addDataSet_(name + std::string("_real"), data.real());
130  addDataSet_(name + std::string("_imag"), data.imag());
131  return;
132  }
137  template <typename LinOp>
138  inline void addDataSet(
139  const std::string& name, const AnsatzSpace<LinOp>& ansatz_space,
140  const Eigen::Matrix<typename LinearOperatorTraits<LinOp>::Scalar,
141  Eigen::Dynamic, Eigen::Dynamic>& coefficients) {
142  // Initialize FunctionEvaluator
143  FunctionEvaluator<LinOp> evaluator(ansatz_space);
144  evaluator.set_function(coefficients);
145 
146  // Define function for FunctionEvaluator
147  typedef typename DifferentialFormTraits<
149  typename LinearOperatorTraits<LinOp>::Scalar>::FunctionSpaceValue
150  ReturnType;
151  constexpr int dimension =
154  FunctionSpaceOutputDimension;
155  std::function<ReturnType(int, const Eigen::Vector2d&)> fun =
156  getEvaluatorFunction_<LinOp, dimension>::get(evaluator);
157 
158  // Define function for FunctionEvaluator
159  addDataSet(name, fun);
160 
161  return;
162  }
163 
167  inline void writeToFile(const std::string& filename) {
168  std::ofstream output;
169  output.open(filename);
170  output << "<VTKFile type=\"PolyData\" version=\"0.1\" "
171  "byte_order=\"LittleEndian\">\n"
172  "<PolyData>\n"
173  "<Piece NumberOfPoints=\" "
174  << points.rows()
175  << "\" NumberOfVerts=\"0\" NumberOfLines=\"0\" NumberOfStrips=\"0\" "
176  "NumberOfPolys=\""
177  << cells.rows()
178  << "\">\n"
179  "<Points>\n"
180  "<DataArray type=\"Float32\" NumberOfComponents=\"3\" "
181  "format=\"ascii\">\n";
182  output << points;
183  output << "</DataArray>\n</Points>";
184  output << "<CellData Scalars=\"patch_number\" Normals=\"cell_normals\">\n"
185  "<DataArray type=\"Int32\" Name=\"patch_number\" "
186  "format=\"ascii\">\n";
187  output << patch_number;
188  output << "</DataArray>\n<DataArray type=\"Float32\" Name=\"cell_normals\" "
189  "NumberOfComponents=\"3\" format=\"ascii\">";
190  output << normals;
191  output << "</DataArray>\n";
192  for (auto data : additionalData) {
193  output << data;
194  }
195  output << "</CellData>\n"
196  "<Polys>\n"
197  "<DataArray type=\"Int32\" Name=\"connectivity\" "
198  "format=\"ascii\">\n";
199  output << cells;
200  output << "</DataArray>\n"
201  "<DataArray type=\"Int32\" Name=\"offsets\" "
202  "format=\"ascii\">\n";
203  for (int i = 0; i < cells.rows(); ++i) {
204  output << (i + 1) * 4;
205  output << "\n";
206  }
207  output << "</DataArray>\n"
208  "</Polys>\n"
209  "</Piece>\n"
210  "</PolyData>\n"
211  "</VTKFile>";
212  output.close();
213  return;
214  }
215  // can be used to clear the additional Data.
216  inline void clearData() {
217  additionalData = {};
218  additionalData.shrink_to_fit();
219  }
220 
221  private:
222  // This routine turns the data of the above DataSet-routines into a string and
223  // stores it.
224  inline void addDataSet_(const std::string& name, const Eigen::MatrixXd& mat) {
225  assert(mat.cols() == 1 || mat.cols() == 3);
226  assert(mat.rows() == cells.rows());
227 
228  const int cols = mat.cols();
229  std::string data_ascii = "<DataArray type=\"Float32\" Name=\"" + name +
230  "\" NumberOfComponents=\"" +
231  std::to_string(mat.cols()) +
232  "\" format=\"ascii\">\n";
233  std::ostringstream out;
234  out.precision(6);
235  for (int i = 0; i < mat.rows(); ++i) {
236  for (int j = 0; j < cols; ++j) {
237  out << std::scientific << mat(i, j);
238  data_ascii.append(std::move(out).str() + " ");
239  out.str("");
240  out.clear();
241  }
242  data_ascii.append("\n");
243  }
244  data_ascii.append("</DataArray>\n");
245  additionalData.push_back(data_ascii);
246  }
247 
248  // generate data for functions living in spatial domains
249  template <typename Scalar, int dim>
250  inline Eigen::Matrix<Scalar, Eigen::Dynamic, dim> getData_(
251  const std::function<
252  Eigen::Matrix<Scalar, dim, 1>(const Eigen::Vector3d&)>& fun) {
253  Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> data(cells.rows(),
254  dim);
255  int k = 0;
256  for (auto e = msh.get_element_tree().cpbegin();
257  e != msh.get_element_tree().cpend(); ++e) {
258  data.row(e->id_) =
259  fun(msh.get_geometry()[e->patch_].eval(e->referenceMidpoint()))
260  .transpose();
261  }
262  return data;
263  }
264  template <typename Scalar>
265  inline Eigen::Matrix<Scalar, Eigen::Dynamic, 1> getData_(
266  std::function<Scalar(const Eigen::Vector3d&)>& fun) {
267  Eigen::Matrix<Scalar, Eigen::Dynamic, 1> data(cells.rows());
268  int k = 0;
269  for (auto e = msh.get_element_tree().cpbegin();
270  e != msh.get_element_tree().cpend(); ++e) {
271  data(e->id_) =
272  fun(msh.get_geometry()[e->patch_].eval(e->referenceMidpoint()));
273  }
274  return data;
275  }
276 
277  // generate data for functions living on patches
278  template <typename Scalar, int dim>
279  inline Eigen::Matrix<Scalar, Eigen::Dynamic, dim> getData_(
280  const std::function<
281  Eigen::Matrix<Scalar, dim, 1>(int, const Eigen::Vector2d&)>& fun) {
282  Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> data(cells.rows(),
283  dim);
284  int k = 0;
285  for (auto e = msh.get_element_tree().cpbegin();
286  e != msh.get_element_tree().cpend(); ++e) {
287  data.row(e->id_) = fun(e->patch_, e->referenceMidpoint()).transpose();
288  }
289  return data;
290  }
291  template <typename Scalar>
292  inline Eigen::Matrix<Scalar, Eigen::Dynamic, 1> getData_(
293  std::function<Scalar(int, const Eigen::Vector2d&)>& fun) {
294  Eigen::Matrix<Scalar, Eigen::Dynamic, 1> data(cells.rows());
295  int k = 0;
296  for (auto e = msh.get_element_tree().cpbegin();
297  e != msh.get_element_tree().cpend(); ++e) {
298  data(e->id_) = fun(e->patch_, e->referenceMidpoint());
299  }
300  return data;
301  }
302 
303  // helper function for FunctionEvaluator based output
304  // template <typename LinOp, typename ReturnType>
305  template <typename LinOp, int size>
306  struct getEvaluatorFunction_ {
307  static std::function<
308  Eigen::Matrix<typename LinearOperatorTraits<LinOp>::Scalar, size, 1>(
309  int, const Eigen::Vector2d&)>
310  get(const FunctionEvaluator<LinOp>& evaluator) {
311  typedef typename LinearOperatorTraits<LinOp>::Scalar Scalar;
312  typedef
313  typename Eigen::Matrix<typename LinearOperatorTraits<LinOp>::Scalar,
314  size, 1>
315  ReturnType;
316  std::function<ReturnType(int, const Eigen::Vector2d&)> fun =
317  [&](int patch_number, const Eigen::Vector2d& reference_domain_point) {
318  return evaluator.evaluateOnPatch(patch_number,
319  reference_domain_point);
320  };
321  return fun;
322  }
323  };
324  template <typename LinOp>
325  struct getEvaluatorFunction_<LinOp, 1> {
326  static std::function<typename LinearOperatorTraits<LinOp>::Scalar(
327  int, const Eigen::Vector2d&)>
328  get(const FunctionEvaluator<LinOp>& evaluator) {
329  typedef typename LinearOperatorTraits<LinOp>::Scalar Scalar;
330  std::function<typename DifferentialFormTraits<
331  LinearOperatorTraits<LinOp>::Form,
332  typename LinearOperatorTraits<LinOp>::Scalar>::
333  FunctionSpaceValue(int, const Eigen::Vector2d&)>
334  fun = [&](int patch_number,
335  const Eigen::Vector2d& reference_domain_point) {
336  return evaluator.evaluateOnPatch(patch_number,
337  reference_domain_point)(0);
338  };
339  return fun;
340  }
341  };
342 
343  ClusterTree msh;
344  Eigen::MatrixXd points;
345  Eigen::MatrixXi cells;
346  Eigen::MatrixXd normals;
347  Eigen::VectorXi patch_number;
348  std::vector<std::string> additionalData;
349 };
350 
351 } // namespace Bembel
352 
353 #endif // BEMBEL_SRC_IO_VTKSURFACEEXPORT_HPP_
void init_ClusterTree(const Geometry &geom, int M)
init
Definition: ClusterTree.hpp:82
const PatchVector & get_geometry() const
Return const reference to the Geometry.
ElementTree & get_element_tree()
getter
Definition: ClusterTree.hpp:95
ElementTreeNode::const_iterator cpbegin() const
Returns an iterator to the beginning of the sequence represented by the leafs as ElementTreeNodes of ...
ElementTreeNode::const_iterator cpend() const
Returns an iterator one past the end of the sequence represented by the leafs as ElementTreeNodes of ...
Eigen::MatrixXd generatePointList(Eigen::VectorXi *idct=nullptr) const
Return the coordinates of all points of the elements.
Eigen::MatrixXi generateElementList() const
Return list of elements containing the indices of the vertices.
this class wraps a GeometryVector and provides some basic functionality, like reading Geometry files
Definition: Geometry.hpp:20
Provides export routines from functions on geometries to the VTK file format.
void addDataSet(const std::string &name, std::function< Eigen::Vector3d(int, const Eigen::Vector2d &)> fun)
Add a function of the given type to the visualization.
void writeToFile(const std::string &filename)
Write geometry with passed visualization data to file.
void addDataSet(const std::string &name, std::function< std::complex< double >(const Eigen::Vector3d &)> fun)
Add a function of the given type to the visualization.
void addDataSet(const std::string &name, std::function< Eigen::Vector3cd(int, const Eigen::Vector2d &)> fun)
Add a function of the given type to the visualization.
void addDataSet(const std::string &name, const AnsatzSpace< LinOp > &ansatz_space, const Eigen::Matrix< typename LinearOperatorTraits< LinOp >::Scalar, Eigen::Dynamic, Eigen::Dynamic > &coefficients)
Add a function given through coefficients of an AnsatzSpace to the visualization.
VTKSurfaceExport(const Geometry &geo, int M)
void addDataSet(const std::string &name, std::function< Eigen::Vector3d(const Eigen::Vector3d &)> fun)
Add a function of the given type to the visualization.
void addDataSet(const std::string &name, std::function< Eigen::Vector3cd(const Eigen::Vector3d &)> fun)
Add a function of the given type to the visualization.
void addDataSet(const std::string &name, std::function< double(int, const Eigen::Vector2d &)> fun)
Add a function of the given type to the visualization.
void addDataSet(const std::string &name, std::function< double(const Eigen::Vector3d &)> fun)
Add a function of the given type to the visualization.
void addDataSet(const std::string &name, std::function< std::complex< double >(int, const Eigen::Vector2d &)> fun)
Add a function of the given type to the visualization.
Routines for the evalutation of pointwise errors.
Definition: AnsatzSpace.hpp:14
struct containing specifications on DifferentialForms, i.e., the function spaces.
struct containing specifications on the linear operator has to be specialized or derived for any part...