Fluid structure interaction suite
grid_generator.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2022 by Luca Heltai
4 //
5 // This file is part of the FSI-suite platform, based on the deal.II library.
6 //
7 // The FSI-suite platform is free software; you can use it, redistribute it,
8 // and/or modify it under the terms of the GNU Lesser General Public License as
9 // published by the Free Software Foundation; either version 3.0 of the License,
10 // or (at your option) any later version. The full text of the license can be
11 // found in the file LICENSE at the top level of the FSI-suite platform
12 // distribution.
13 //
14 // ---------------------------------------------------------------------
15 
17 
18 #include <deal.II/grid/grid_in.h>
19 #include <deal.II/grid/grid_out.h>
20 
23 #ifdef DEAL_II_WITH_OPENCASCADE
24 # include <BRepBndLib.hxx>
25 # include <Bnd_Box.hxx>
26 # include <TopoDS.hxx>
27 #endif
28 
29 #include <boost/algorithm/string/case_conv.hpp>
30 #include <boost/archive/binary_iarchive.hpp>
31 #include <boost/archive/binary_oarchive.hpp>
32 #include <boost/archive/text_iarchive.hpp>
33 #include <boost/archive/text_oarchive.hpp>
34 
35 using namespace dealii;
36 
37 namespace ParsedTools
38 {
39  template <int dim, int spacedim>
41  const std::string &prm_section_path,
42  const std::string &grid_generator_function,
43  const std::string &grid_generator_arguments,
44  const std::string &output_file_name,
45  const bool transform_to_simplex_grid,
46  const unsigned int initial_grid_refinement)
47  : ParameterAcceptor(prm_section_path)
48  , grid_generator_function(grid_generator_function)
49  , grid_generator_arguments(grid_generator_arguments)
50  , output_file_name(output_file_name)
51  , transform_to_simplex_grid(transform_to_simplex_grid)
52  , initial_grid_refinement(initial_grid_refinement)
53  {
54  add_parameter("Input name", this->grid_generator_function);
55  add_parameter("Arguments", this->grid_generator_arguments);
56  add_parameter("Output name", this->output_file_name);
57  add_parameter("Transform to simplex grid", this->transform_to_simplex_grid);
58  add_parameter("Initial grid refinement", this->initial_grid_refinement);
59  }
60 
61 
62  template <int dim, int spacedim>
63  void
65  dealii::Triangulation<dim, spacedim> &tria) const
66  {
67  // TimerOutput::Scope timer_section(timer, "GridGenerator::generate");
68  const auto ext =
69  boost::algorithm::to_lower_copy(grid_generator_function.substr(
70  grid_generator_function.find_last_of('.') + 1));
71 
72  // No extension was found: use grid generator functions
73  if (ext == boost::algorithm::to_lower_copy(grid_generator_function) ||
74  ext == "")
75  {
76  dealii::GridGenerator::generate_from_name_and_arguments(
77  tria, grid_generator_function, grid_generator_arguments);
78  }
79  else
80  {
81  // grid_generator_function is a filename. Use GridIn
82  GridIn<dim, spacedim> gi(tria);
83  try
84  {
85  // Use gmsh api by default
86  if (ext == "msh")
87  gi.read_msh(grid_generator_function);
88  // Otherwise try deal.II stdandard way of reading grids
89  else
90  gi.read(grid_generator_function); // Try default ways
91  }
92  catch (std::exception &exc)
93  {
94  std::cerr << std::endl
95  << std::endl
96  << "----------------------------------------------------"
97  << std::endl;
98  std::cerr << "Exception on processing: " << std::endl
99  << exc.what() << std::endl
100  << "Trying other strategies." << std::endl
101  << "----------------------------------------------------"
102  << std::endl;
103  // Attempt some of the other things manually
104  std::ifstream in(grid_generator_function);
105  AssertThrow(in, ExcIO());
106  if (ext == "ar")
107  {
108  boost::archive::text_iarchive ia(in);
109  tria.load(ia, 0);
110  }
111  else if (ext == "bin")
112  {
113  boost::archive::binary_iarchive ia(in);
114  tria.load(ia, 0);
115  }
116  else
117  {
118  in.close();
119  // try assimp reader as a last resort
120  gi.read_assimp(grid_generator_function);
121  }
122  }
123 
124 #ifdef DEAL_II_WITH_OPENCASCADE
125  // Only if we read a file, we check if arguments can be interpreted as
126  // manifold CAD files.
127  using map_type = std::map<types::manifold_id, std::string>;
128  using Converter = Patterns::Tools::Convert<map_type>;
129  for (const auto &[manifold_id, cad_file_name] :
130  Converter::to_value(grid_generator_arguments))
131  {
132  const auto extension = boost::algorithm::to_lower_copy(
133  cad_file_name.substr(cad_file_name.find_last_of('.') + 1));
134  TopoDS_Shape shape;
135  if (extension == "iges" || extension == "igs")
136  shape = OpenCASCADE::read_IGES(cad_file_name, 1.0);
137  else if (extension == "step" || extension == "stp")
138  shape = OpenCASCADE::read_STEP(cad_file_name, 1.0);
139  else if (extension == "stl")
140  shape = OpenCASCADE::read_STL(cad_file_name);
141  else
142  AssertThrow(false,
143  ExcNotImplemented("We found an extension that we "
144  "do not recognize as a CAD file "
145  "extension. Bailing out."));
146  if constexpr (spacedim > 1)
147  {
148  const auto [n_faces, n_edges, n_vertices] =
150  deallog << "Manifold id: " << manifold_id << std::endl
151  << ", attached to CAD File " << cad_file_name
152  << std::endl;
153  deallog.push(cad_file_name);
154  deallog << "Number of faces: " << n_faces << std::endl
155  << "Number of edges: " << n_edges << std::endl
156  << "Number of vertices: " << n_vertices << std::endl;
157  deallog.push("Bounding box");
158 
159  double Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
160 
161  // Compute the parameters
162  Bnd_Box box;
163  BRepBndLib::Add(shape, box);
164  box.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
165  deallog << "Lower left corner: " << Xmin << ", " << Ymin << ", "
166  << Zmin << std::endl
167  << "Upper right corner: " << Xmax << ", " << Ymax
168  << ", " << Zmax << std::endl;
169  deallog.pop();
170  deallog.pop();
171  if (n_faces == 0 && n_edges > 0)
172  tria.set_manifold(
173  manifold_id,
175  shape));
176  else if constexpr (spacedim == 3)
177  {
178  tria.set_manifold(
179  manifold_id,
181  spacedim>(
182  shape));
183  }
184  else
185  tria.set_manifold(
186  manifold_id,
188  TopoDS::Face(shape)));
189  }
190  }
191 #else
192  AssertThrow(grid_generator_arguments == "",
193  ExcNotImplemented("Generation of manifolds failed. We need "
194  "OPENCASCADE to do this."));
195 #endif
196  }
197 
198  // If the user wants to transform the grid to a simplex grid, do so
199  if (transform_to_simplex_grid == true &&
200  tria.all_reference_cells_are_hyper_cube() == true)
201  {
203  tmp.copy_triangulation(tria);
204  tria.clear();
205  dealii::GridGenerator::convert_hypercube_to_simplex_mesh(tmp, tria);
206 
207  // Also copy all manifold ids
208  for (const auto i : tmp.get_manifold_ids())
209  if (i != numbers::flat_manifold_id)
210  tria.set_manifold(i, tmp.get_manifold(i));
211  }
212 
213 
214  // Write the grid before refining it.
215  write(tria);
216  tria.refine_global(initial_grid_refinement);
217  }
218 
219 
220 
221  template <int dim, int spacedim>
222  void
224  const dealii::Triangulation<dim, spacedim> &tria,
225  const std::string &filename) const
226  {
227  const std::string outname = filename != "" ? filename : output_file_name;
228  if (outname != "")
229  {
230  const auto ext = boost::algorithm::to_lower_copy(
231  outname.substr(outname.find_last_of('.') + 1));
232 
233  GridOut go;
234  if (ext == "msh")
235  go.write_msh(tria, outname); // prefer msh api
236  else
237  {
238  std::ofstream out(outname);
239  AssertThrow(out, ExcIO());
240 
241  go.set_flags(GridOutFlags::Msh(true, true));
242  go.set_flags(GridOutFlags::Ucd(false, true, true));
243  go.set_flags(GridOutFlags::Vtu(true));
244 
245  if (ext == "vtk")
246  go.write_vtk(tria, out);
247  else if (ext == "vtu")
248  go.write_vtu(tria, out);
249  else if (ext == "ucd" || ext == "inp")
250  go.write_ucd(tria, out);
251  else if (ext == "vtu")
252  go.write_vtu(tria, out);
253  else if (ext == "ar")
254  {
255  boost::archive::text_oarchive oa(out);
256  tria.save(oa, 0);
257  }
258  else if (ext == "bin")
259  {
260  boost::archive::binary_oarchive oa(out);
261  tria.save(oa, 0);
262  }
263  else
264  Assert(false, ExcNotImplemented());
265  out.close();
266  }
267  }
268  }
269 
270 
271  template class GridGenerator<1, 1>;
272  template class GridGenerator<1, 2>;
273  template class GridGenerator<1, 3>;
274  template class GridGenerator<2, 2>;
275  template class GridGenerator<2, 3>;
276  template class GridGenerator<3, 3>;
277 
278 } // namespace ParsedTools
void read_assimp(const std::string &filename, const unsigned int mesh_index=numbers::invalid_unsigned_int, const bool remove_duplicates=true, const double tol=1e-12, const bool ignore_unsupported_element_types=true)
void read_msh(std::istream &in)
void read(std::istream &in, Format format=Default)
void set_flags(const GridOutFlags::DX &flags)
void write_vtk(const Triangulation< dim, spacedim > &tria, std::ostream &out) const
void write_msh(const Triangulation< dim, spacedim > &tria, std::ostream &out) const
void write_vtu(const Triangulation< dim, spacedim > &tria, std::ostream &out) const
void write_ucd(const Triangulation< dim, spacedim > &tria, std::ostream &out) const
void push(const std::string &text)
void pop()
void add_parameter(const std::string &entry, ParameterType &parameter, const std::string &documentation="", ParameterHandler &prm_=prm, const Patterns::PatternBase &pattern=*Patterns::Tools::Convert< ParameterType >::to_pattern())
virtual void copy_triangulation(const Triangulation< dim, spacedim > &other_tria)
GridGenerator class.
void generate(Triangulation< dim, spacedim > &tria) const
Fill a triangulation according to the parsed parameters.
void write(const Triangulation< dim, spacedim > &tria, const std::string &filename="") const
Write the given Triangulation to the output file specified in Output file name, or in the optional fi...
static ::ExceptionBase & ExcIO()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertThrow(cond, exc)
const Manifold< dim, spacedim > & get_manifold(const types::manifold_id number) const
virtual std::vector< types::manifold_id > get_manifold_ids() const
LogStream deallog
std::tuple< unsigned int, unsigned int, unsigned int > count_elements(const TopoDS_Shape &shape)
TopoDS_Shape read_STEP(const std::string &filename, const double scale_factor=1e-3)
TopoDS_Shape read_STL(const std::string &filename)
TopoDS_Shape read_IGES(const std::string &filename, const double scale_factor=1e-3)
We collect in this namespace some wrappers around commonly used deal.II classes, derived from the Par...
const types::manifold_id flat_manifold_id