[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
gmsh_out.cpp
1 #include <float.h>
2 #include <string>
3 
4 #include <deal.II/numerics/data_out.h>
5 #include <deal.II/grid/tria.h>
6 
7 #include <deal.II/base/tensor.h>
8 #include <deal.II/base/symmetric_tensor.h>
9 
10 #include "gmsh_out.h"
11 
12 namespace PHiLiP {
13 
14 namespace GridRefinement {
15 
16 /* Set of functions for outputting necessary data to pass to GMSH mesh generators
17  * Need 4 sets of output types
18  * 1D:
19  * SL - Scalar Line
20  * SP - Scalar Point
21  * VL - Vector Line
22  * VP - Vector Point
23  * 2D:
24  * SQ - Scalar Quad
25  * SP - Scalar Point
26  * VQ - Vector Quad
27  * VP - Vector Point
28  * 3D:
29  * SH - Scalar Hex
30  * SP - Scalar Point
31  * VH - Vector Hex
32  * VP - Vector Point
33  *
34  * Control this output based on the same general form as used in DEALII::DataOutBase
35  */
36 
37 // file for writing SQ output
38 
39 template <int dim, typename real>
41  const dealii::Triangulation<dim, dim> &tria,
42  dealii::Vector<real> data,
43  std::ostream & out)
44 {
45  // get positions
46  // const std::vector<dealii::Point<dim>> &vertices = tria.get_vertices();
47  // const std::vector<bool> & vertex_used = tria.get_used_vertices();
48 
49  const unsigned int n_vertices = tria.n_used_vertices();
50 
51  typename dealii::Triangulation<dim, dim>::active_cell_iterator cell =
52  tria.begin_active();
53  const typename dealii::Triangulation<dim, dim>::active_cell_iterator endc =
54  tria.end();
55 
56  // write header
57  out << "/*********************************** " << '\n'
58  << " * BACKGROUND MESH FIELD GENERATED * " << '\n'
59  << " * AUTOMATICALLY BY PHiLiP LIBRARY * " << '\n'
60  << " ***********************************/" << '\n';
61 
62  // number of vertices
63  out << "// File contains n_vertices = " << n_vertices << '\n' << '\n';
64 
65  // write the "view" header
66  out << "View \"background mesh\" {" << '\n';
67 
68  // writing the main body
69  // SQ(x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4){v1,v2,v3,v4};
70  for(cell = tria.begin_active(); cell!=endc; ++cell){
71  if(!cell->is_locally_owned()) continue;
72 
73  // select the output type
74  if(dim == 2)
75  out << "SQ(";
76  if(dim == 3)
77  out << "SH(";
78 
79  // writing the coordinates
80  for(unsigned int vertex = 0; vertex < dealii::GeometryInfo<dim>::vertices_per_cell; ++vertex){
81  // Fix for the difference in numbering orders (CCW)
82  // DEALII: 2D=[[0,1],[2,3]], 3D=[[[0,1],[2,3]],[[4,5],[6,7]]]
83  // GMSH: 2D=[[0,1],[3,2]], 3D=[[[0,1],[3,2]],[[4,5],[7,6]]]
84  dealii::Point<dim> pos;
85  if((vertex+2)%4 == 0){ // (2,6) -> (3,7)
86  pos = cell->vertex(vertex+1);
87  }else if((vertex+1)%4 == 0){ // (3,7) -> (2,6)
88  pos = cell->vertex(vertex-1);
89  }else{
90  pos = cell->vertex(vertex);
91  }
92 
93  if(vertex != 0){out << ",";}
94 
95  // x
96  if(dim >= 1){out << pos[0] << ",";}
97  else {out << 0 << ",";}
98  // y
99  if(dim >= 2){out << pos[1] << ",";}
100  else {out << 0 << ",";}
101  // z
102  if(dim >= 3){out << pos[2];}
103  else {out << 0;}
104  }
105 
106  out << "){";
107 
108  // writing the data values
109  // for now just putting 1.0
110  // out << "1.0,2.0,3.0,4.0";
111  // for(unsigned int vertex = 0; vertex < dealii::GeometryInfo<dim>::vertices_per_cell; ++vertex)
112  // {
113  // // Fix for the difference in numbering orders (CCW)
114  // // DEALII: 2D=[[0,1],[2,3]], 3D=[[[0,1],[2,3]],[[4,5],[6,7]]]
115  // // GMSH: 2D=[[0,1],[3,2]], 3D=[[[0,1],[3,2]],[[4,5],[7,6]]]
116  // dealii::Point<dim> pos;
117  // if((vertex+2)%4 == 0){ // (2,6) -> (3,7)
118  // pos = cell->vertex(vertex+1);
119  // }else if((vertex+1)%4 == 0){ // (3,7) -> (2,6)
120  // pos = cell->vertex(vertex-1);
121  // }else{
122  // pos = cell->vertex(vertex);
123  // }
124  // // just going to assume the dim is 2 for now
125  // if(vertex != 0){out << ",";}
126  // if(dim == 2){
127  // double x = pos[0], y = pos[1];
128  // double v = x*y+0.01;
129  // out<<v;
130  // }
131  // }
132 
133  // getting the cellwise value
134  real v = data[cell->active_cell_index()];
135  real scale = 1; // no subdivision
136  for(unsigned int vertex = 0; vertex < dealii::GeometryInfo<dim>::vertices_per_cell; ++vertex){
137  if(vertex != 0){out << ",";}
138  out << v*scale;
139  }
140 
141  out << "};" << '\n';
142  }
143 
144  // write the "view footer"
145  out << "}; //View \"background mesh\" " << '\n';
146 
147  out << std::flush;
148 }
149 
150 // writing anisotropic (tensor based) .pos file for use with gmsh
151 template <int dim, typename real>
153  const dealii::Triangulation<dim,dim>& tria,
154  const std::vector<dealii::SymmetricTensor<2,dim,real>>& data,
155  std::ostream& out,
156  const int p_scale)
157 {
158  const unsigned int n_vertices = tria.n_used_vertices();
159 
160  typename dealii::Triangulation<dim, dim>::active_cell_iterator cell =
161  tria.begin_active();
162  const typename dealii::Triangulation<dim, dim>::active_cell_iterator endc =
163  tria.end();
164 
165  // write header
166  out << "/*********************************** " << '\n'
167  << " * BACKGROUND MESH FIELD GENERATED * " << '\n'
168  << " * AUTOMATICALLY BY PHiLiP LIBRARY * " << '\n'
169  << " ***********************************/" << '\n';
170 
171  // number of vertices
172  out << "// File contains n_vertices = " << n_vertices << '\n' << '\n';
173 
174  // write the "view" header
175  out << "View \"background mesh\" {" << '\n';
176 
177  // writing the main body
178  // TT(x1,y1,z1,x2,y2,z2,x3,y3,z3){M1, M2, M3};
179  // where Mi = [m11, m12, m13, m21, m22, m23, m31, m32, m33];
180  for(cell = tria.begin_active(); cell!=endc; ++cell){
181  if(!cell->is_locally_owned()) continue;
182 
183  // cell-wise value
184  const dealii::Tensor<2,dim,real> val = data[cell->active_cell_index()];
185 
186  // only implemented for dim == 2 currently
187  if(dim == 2){
188 
189  // writing the coordinates
190  std::vector<dealii::Point<dim>> vertices;
191  vertices.reserve(dealii::GeometryInfo<dim>::vertices_per_cell);
192  for(unsigned int vertex = 0; vertex < dealii::GeometryInfo<dim>::vertices_per_cell; ++vertex){
193  // Fix for the difference in numbering orders (CCW)
194  // DEALII: 2D=[[0,1],[2,3]], 3D=[[[0,1],[2,3]],[[4,5],[6,7]]]
195  // GMSH: 2D=[[0,1],[3,2]], 3D=[[[0,1],[3,2]],[[4,5],[7,6]]]
196  dealii::Point<dim> pos;
197  if((vertex+2)%4 == 0){ // (2,6) -> (3,7)
198  pos = cell->vertex(vertex+1);
199  }else if((vertex+1)%4 == 0){ // (3,7) -> (2,6)
200  pos = cell->vertex(vertex-1);
201  }else{
202  pos = cell->vertex(vertex);
203  }
204 
205  vertices.push_back(pos);
206  }
207 
208  // splitting the quad into two triangles and output
209  // forming two triangels [0,3,2] and [0,2,1]
210  for(const auto& tri:
211  std::array<std::array<int,3>,2>{{
212  {{0,3,2}},
213  {{0,2,1}} }}){
214  // writing the coordinates
215  out << "TT(";
216  for(unsigned int i = 0; i < tri.size(); ++i){
217  if(i != 0){out << ",";}
218 
219  // x
220  dealii::Point<dim> pos = vertices[tri[i]];
221  if(dim >= 1){out << pos[0] << ",";}
222  else {out << 0 << ",";}
223  // y
224  if(dim >= 2){out << pos[1] << ",";}
225  else {out << 0 << ",";}
226  // z
227  if(dim >= 3){out << pos[2];}
228  else {out << 0;}
229  }
230 
231  // writing the tensor data (for each node)
232  out << "){";
233  bool flag = false;
234  for(unsigned int vertex = 0; vertex < tri.size(); ++vertex){
235 
236  // writing the tensor itself, always 3x3
237  const unsigned int N = 3;
238 
239  // empirical scaling for the complexity match
240  double scale = 1.0;
241  if(p_scale == 1){
242  scale = 0.25*0.5/sqrt(2.0);
243  }else if(p_scale == 2){
244  scale = 0.25/sqrt(3.0);
245  }else if(p_scale == 3){
246  scale = 0.25/sqrt(2.0);
247  }
248 
249  for(unsigned int i = 0; i < N; ++i){
250  for(unsigned int j = 0; j < N; ++j){
251 
252  // only skipping comma on first point
253  if(flag){
254  out << ",";
255  }else{
256  flag = true;
257  }
258 
259  // data only specified for upper dim x dim
260  if( (i < dim) && (j < dim) ){
261  out << scale*val[i][j];
262  }else{
263  // adding 1.0 along diagonal
264  if( i == j ){
265  out << "1.0";
266  }else{
267  out << "0";
268  }
269  }
270 
271  }
272  }
273  }
274 
275  out << "};" << '\n';
276 
277  }
278 
279  }
280  }
281 
282  // write the "view footer"
283  out << "}; //View \"background mesh\" " << '\n';
284  out << std::flush;
285 
286 }
287 
288 // writing the geo file which calls the meshing
289 // need to add a set of flags here describing what to write
290 template <int dim, typename real>
292  std::vector<std::string> &posFile_vec,
293  std::ostream & out)
294 {
295  // write header
296  out << "/*********************************** " << '\n'
297  << " * MESH GEOMETRY FILE GENERATED * " << '\n'
298  << " * AUTOMATICALLY BY PHiLiP LIBRARY * " << '\n'
299  << " ***********************************/" << '\n' << '\n';
300 
301  // the background field should fully specify the mesh size, points seem to fix some skewness
302  out << "Mesh.CharacteristicLengthFromPoints = 1;" << '\n'
303  << "Mesh.CharacteristicLengthFromCurvature = 0;" << '\n'
304  << "Mesh.CharacteristicLengthExtendFromBoundary = 0;" << '\n' << '\n';
305 
306  // default is the advancing delquad
307  // TODO: add parameter file for other options (and 3d)
308  out << "Mesh.Algorithm = 8;" << '\n'
309  << "Mesh.RecombinationAlgorithm = 3;" << '\n'
310  << "Mesh.RecombineAll = 1;" << '\n' << '\n';
311 
312  // writing the geometry of the part
313  // TODO: read from a parameter list what shape (could be CAD)
314  write_geo_hyper_cube(0.0, 1.0, out);
315 
316  // writing the information about the recombination
317  // TODO: read from a parameter list what schemes
318  out << "// Merging the background mesh and recombine" << '\n';
319  for(unsigned int ifile = 0; ifile < posFile_vec.size(); ++ifile)
320  out << "Merge \"" << posFile_vec[ifile] << "\";" << '\n';
321 
322  // combining the views
323  out << "Combine Views;" << '\n';
324 
325  // this line may be dependent on the name in the other file
326  out << "Background Mesh View[0];" << '\n';
327 
328  out << std::flush;
329 }
330 
331 // writing the (anisotropic) geo file
332 template <int dim, typename real>
334  std::vector<std::string> &posFile_vec,
335  std::ostream & out)
336 {
337  // write header
338  out << "/*********************************** " << '\n'
339  << " * MESH GEOMETRY FILE GENERATED * " << '\n'
340  << " * AUTOMATICALLY BY PHiLiP LIBRARY * " << '\n'
341  << " ***********************************/" << '\n' << '\n';
342 
343  // the background field should fully specify the mesh size, points seem to fix some skewness
344  out << "Mesh.CharacteristicLengthFromPoints = 1;" << '\n'
345  << "Mesh.CharacteristicLengthFromCurvature = 0;" << '\n'
346  << "Mesh.CharacteristicLengthExtendFromBoundary = 0;" << '\n' << '\n';
347 
348  // default is the BAMG for anisotropy
349  out << "Mesh.Algorithm = 7;" << '\n'
350  // << "Mesh.SmoothRatio = 1.5;" << '\n'
351  << "Mesh.RecombinationAlgorithm = 2;" << '\n'
352  << "Mesh.RecombineAll = 1;" << '\n' << '\n';
353 
354  // writing the geometry of the part
355  // TODO: read from a parameter list what shape (could be CAD)
356  write_geo_hyper_cube(0.0, 1.0, out);
357 
358  // writing the information about the recombination
359  // TODO: read from a parameter list what schemes
360  out << "// Merging the background mesh and recombine" << '\n';
361  for(unsigned int ifile = 0; ifile < posFile_vec.size(); ++ifile)
362  out << "Merge \"" << posFile_vec[ifile] << "\";" << '\n';
363 
364  // combining the views
365  out << "Combine Views;" << '\n';
366 
367  // this line may be dependent on the name in the other file
368  out << "Background Mesh View[0];" << '\n';
369 
370  out << std::flush;
371 }
372 
373 // writes the geometry of a hypercube to the file as the domain to be meshed
374 template <int dim, typename real>
376  const double left,
377  const double right,
378  std::ostream &out,
379  const bool colorize)
380 {
381  // placing the poins at each of the corners (can be in any order)
382  // splitting the dimensional cases for easier reading
383 
384  if(dim == 2){
385  out << "// Points" << '\n';
386  out << "Point(1)={" << left << "," << left << "," << 0 << "};" << '\n';
387  out << "Point(2)={" << right << "," << left << "," << 0 << "};" << '\n';
388  out << "Point(3)={" << right << "," << right << "," << 0 << "};" << '\n';
389  out << "Point(4)={" << left << "," << right << "," << 0 << "};" << '\n';
390  out << '\n';
391 
392  out << "// Lines" << '\n';
393  out << "Line(1)={1,2};" << '\n';
394  out << "Line(2)={2,3};" << '\n';
395  out << "Line(3)={3,4};" << '\n';
396  out << "Line(4)={4,1};" << '\n';
397  out << '\n';
398 
399  out << "// Loop" << '\n';
400  out << "Line Loop(1)={1,2,3,4};" << '\n';
401  out << '\n';
402 
403  out << "// Surface" << '\n';
404  out << "Plane Surface(1) = {1};" << '\n';
405  out << '\n';
406 
407  // colorizes the boundary in the style of DEALII internal numbering
408  if(colorize){
409  out << "// Colorize" << '\n';
410  out << "Physical Curve (2) = {1};" << '\n';
411  out << "Physical Curve (1) = {2};" << '\n';
412  out << "Physical Curve (3) = {3};" << '\n';
413  out << "Physical Curve (0) = {4};" << '\n';
414  out << '\n';
415  }
416 
417  out<<"Physical Surface(\"surf1\", 5) = {1};"<<'\n';
418  }
419 
420 }
421 
422 template <int dim, typename real>
424  std::string geo_name,
425  std::string output_name)
426 {
427 #if ENABLE_GMSH && defined GMSH_PATH
428  // enabled, call with suitable args
429  std::string args = " " + geo_name + " -" + std::to_string(dim) + " -save_all -o " + output_name;
430  std::string cmd = GMSH_PATH + args;
431  std::cout << "Command is: " << cmd << '\n';
432  int ret = std::system(cmd.c_str());
433  (void) ret;
434  return 1;
435 #else
436  // disabled
437  (void) geo_name;
438  (void) output_name;
439  std::cerr << "Error: Call to gmsh without gmsh enabled." << std::endl;
440  std::cerr << " Please set ENABLE_GMSH and GMSH_PATH and try again." << std::endl;
441  return 0;
442 #endif
443 }
444 
445 
446 template class GmshOut <PHILIP_DIM, double>;
447 template class GmshOut <PHILIP_DIM, float>;
448 
449 } // namespace GridRefinement
450 
451 } //namespace PHiLiP
static int call_gmsh(std::string geo_name, std::string output_name)
Performs command line call to GMSH for grid generation (if availible)
Definition: gmsh_out.cpp:423
Files for the baseline physics.
Definition: ADTypes.hpp:10
static void write_geo_hyper_cube(const double left, const double right, std::ostream &out, const bool colorize=true)
Writes the part of the .geo file associated wit the hyperdube geometry.
Definition: gmsh_out.cpp:375
static void write_geo(std::vector< std::string > &posFile_vec, std::ostream &out)
Writes the central .geo file for call to GMSH on main process with isotropic quad meshing...
Definition: gmsh_out.cpp:291
static void write_pos_anisotropic(const dealii::Triangulation< dim, dim > &tria, const std::vector< dealii::SymmetricTensor< 2, dim, real >> &data, std::ostream &out, const int p_scale=1)
Write anisotropic tensor .pos file for use with GMSH.
Definition: gmsh_out.cpp:152
static void write_geo_anisotropic(std::vector< std::string > &posFile_vec, std::ostream &out)
Writes the central .geo file for call to GMSH on main process with anisotropic quad meshing...
Definition: gmsh_out.cpp:333
static void write_pos(const dealii::Triangulation< dim, dim > &tria, dealii::Vector< real > data, std::ostream &out)
Write scalar .pos file for use with GMSH.
Definition: gmsh_out.cpp:40