SemiDiscreteOT 1.0
Semi-Discrete Optimal Transport Library
Loading...
Searching...
No Matches
MeshManager.templates.h
Go to the documentation of this file.
1#ifndef MESH_MANAGER_TEMPLATES_H
2#define MESH_MANAGER_TEMPLATES_H
3
4// This file contains the template implementations for the MeshManager class.
5// See MeshManager.h for the class documentation.
6
7template <int dim, int spacedim>
9 : mpi_communicator(comm)
10 , n_mpi_processes(Utilities::MPI::n_mpi_processes(comm))
11 , this_mpi_process(Utilities::MPI::this_mpi_process(comm))
12 , pcout(std::cout, this_mpi_process == 0)
13{}
14
15template <int dim, int spacedim>
16template <typename TriangulationType>
17void MeshManager<dim, spacedim>::generate_mesh(TriangulationType& tria,
18 const std::string& grid_generator_function,
19 const std::string& grid_generator_arguments,
20 const unsigned int n_refinements,
21 const bool use_tetrahedral_mesh)
22{
23 if constexpr (std::is_same_v<TriangulationType, parallel::fullydistributed::Triangulation<dim, spacedim>>) {
24 // For fullydistributed triangulation, first create a serial triangulation
25 Triangulation<dim, spacedim> serial_tria;
26 GridGenerator::generate_from_name_and_arguments(
27 serial_tria,
28 grid_generator_function,
29 grid_generator_arguments);
30
31 if (grid_generator_function == "hyper_ball")
32 {
33 Point<spacedim> center{0., 0., 0.};
34 for (const auto &cell : serial_tria.active_cell_iterators())
35 if (center.distance(cell->center()) > cell->diameter() / 10)
36 cell->set_all_manifold_ids(0);
37 }
38
39 serial_tria.refine_global(n_refinements);
40
41 if (use_tetrahedral_mesh && dim == 3 && spacedim == 3) {
42 GridGenerator::convert_hypercube_to_simplex_mesh(serial_tria, serial_tria);
43 }
44
45 // Set up the partitioner to use z-order curve
46 tria.set_partitioner([](Triangulation<dim, spacedim>& tria_to_partition, const unsigned int n_partitions) {
47 GridTools::partition_triangulation_zorder(n_partitions, tria_to_partition);
48 }, TriangulationDescription::Settings::construct_multigrid_hierarchy);
49
50 // Create the construction data
51 auto construction_data = TriangulationDescription::Utilities::create_description_from_triangulation(
52 serial_tria, mpi_communicator,
53 TriangulationDescription::Settings::construct_multigrid_hierarchy);
54
55 // Actually create the distributed triangulation
56 tria.create_triangulation(construction_data);
57 } else {
58 // For regular triangulation
59 GridGenerator::generate_from_name_and_arguments(
60 tria,
61 grid_generator_function,
62 grid_generator_arguments);
63
64 if (grid_generator_function == "hyper_ball")
65 {
66 Point<spacedim> center{0., 0., 0.};
67 for (const auto &cell : tria.active_cell_iterators())
68 if (center.distance(cell->center()) > cell->diameter() / 10)
69 cell->set_all_manifold_ids(0);
70 }
71
72 tria.refine_global(n_refinements);
73
74 if (use_tetrahedral_mesh && dim == 3 && spacedim == 3) {
75 GridGenerator::convert_hypercube_to_simplex_mesh(tria, tria);
76 }
77 }
78}
79
80template <int dim, int spacedim>
81void MeshManager<dim, spacedim>::load_source_mesh(parallel::fullydistributed::Triangulation<dim, spacedim>& source_mesh,
82 const std::string& source_file)
83{
84 // First load source mesh into a serial triangulation
85 Triangulation<dim, spacedim> serial_source;
86 GridIn<dim, spacedim> grid_in_source;
87 grid_in_source.attach_triangulation(serial_source);
88 bool source_loaded = false;
89
90 // If custom file path is provided, try to load it
91 if (!source_file.empty()) {
92 std::ifstream input_file(source_file);
93 if (input_file.good()) {
94 try {
95 // Determine file format from extension
96 std::string extension = source_file.substr(source_file.find_last_of(".") + 1);
97 if (extension == "vtk") {
98 grid_in_source.read_vtk(input_file);
99 } else if (extension == "msh") {
100 grid_in_source.read_msh(input_file);
101 } else {
102 throw std::runtime_error("Unsupported file format: " + extension);
103 }
104 source_loaded = true;
105 pcout << "Source mesh loaded from custom file: " << source_file << std::endl;
106 } catch (const std::exception& e) {
107 pcout << "Failed to load source mesh from custom file: " << e.what() << std::endl;
108 }
109 } else {
110 pcout << "Could not open custom source mesh file: " << source_file << std::endl;
111 }
112 }
113
114 // If custom file loading failed or no custom file provided, try default locations
115 if (!source_loaded) {
116 // First try VTK
117 std::ifstream in_vtk_source(mesh_directory + "/source.vtk");
118 if (in_vtk_source.good()) {
119 try {
120 grid_in_source.read_vtk(in_vtk_source);
121 source_loaded = true;
122 pcout << "Source mesh loaded from VTK format" << std::endl;
123 } catch (const std::exception& e) {
124 pcout << "Failed to load source mesh from VTK format: " << e.what() << std::endl;
125 }
126 }
127
128 // If VTK failed, try MSH
129 if (!source_loaded) {
130 std::ifstream in_msh_source(mesh_directory + "/source.msh");
131 if (in_msh_source.good()) {
132 try {
133 grid_in_source.read_msh(in_msh_source);
134 source_loaded = true;
135 pcout << "Source mesh loaded from MSH format" << std::endl;
136 } catch (const std::exception& e) {
137 pcout << "Failed to load source mesh from MSH format: " << e.what() << std::endl;
138 }
139 }
140 }
141 }
142
143 if (!source_loaded) {
144 throw std::runtime_error("Failed to load source mesh from either custom file or default locations");
145 }
146
147 // Partition the serial source mesh using z-order curve
148 GridTools::partition_triangulation_zorder(n_mpi_processes, serial_source);
149
150 // Convert serial source mesh to fullydistributed without multigrid hierarchy
151 auto construction_data = TriangulationDescription::Utilities::create_description_from_triangulation(
152 serial_source, mpi_communicator,
153 TriangulationDescription::Settings::default_setting);
154 source_mesh.create_triangulation(construction_data);
155}
156
157template <int dim, int spacedim>
158void MeshManager<dim, spacedim>::load_target_mesh(Triangulation<dim, spacedim>& target_mesh)
159{
160 // Only rank 0 loads the target mesh
161 if (this_mpi_process != 0) {
162 return;
163 }
164
165 // Load target mesh (stays serial)
166 GridIn<dim, spacedim> grid_in_target;
167 grid_in_target.attach_triangulation(target_mesh);
168 bool target_loaded = false;
169
170 // Try VTK for target
171 std::ifstream in_vtk_target(mesh_directory + "/target.vtk");
172 if (in_vtk_target.good()) {
173 try {
174 grid_in_target.read_vtk(in_vtk_target);
175 target_loaded = true;
176 pcout << "Target mesh loaded from VTK format" << std::endl;
177 } catch (const std::exception& e) {
178 pcout << "Failed to load target mesh from VTK format: " << e.what() << std::endl;
179 }
180 }
181
182 // If VTK failed, try MSH for target
183 if (!target_loaded) {
184 std::ifstream in_msh_target(mesh_directory + "/target.msh");
185 if (in_msh_target.good()) {
186 try {
187 grid_in_target.read_msh(in_msh_target);
188 target_loaded = true;
189 pcout << "Target mesh loaded from MSH format" << std::endl;
190 } catch (const std::exception& e) {
191 pcout << "Failed to load target mesh from MSH format: " << e.what() << std::endl;
192 }
193 }
194 }
195
196 if (!target_loaded) {
197 throw std::runtime_error("Failed to load target mesh from either VTK or MSH format");
198 }
199}
200
201template <int dim, int spacedim>
202void MeshManager<dim, spacedim>::load_mesh_at_level(parallel::fullydistributed::Triangulation<dim, spacedim>& source_mesh,
203 DoFHandler<dim, spacedim>& dof_handler_source,
204 const std::string& mesh_file)
205{
206 pcout << "Attempting to load mesh from: " << mesh_file << std::endl;
207
208 // Check if file exists
209 if (!std::filesystem::exists(mesh_file)) {
210 throw std::runtime_error("Mesh file does not exist: " + mesh_file);
211 }
212
213 // Check if file is readable and non-empty
214 std::ifstream input(mesh_file);
215 if (!input.good()) {
216 throw std::runtime_error("Cannot open mesh file: " + mesh_file);
217 }
218
219 input.seekg(0, std::ios::end);
220 if (input.tellg() == 0) {
221 throw std::runtime_error("Mesh file is empty: " + mesh_file);
222 }
223 input.seekg(0, std::ios::beg);
224
225 try {
226 // First load into a serial triangulation
227 Triangulation<dim, spacedim> serial_source;
228 GridIn<dim, spacedim> grid_in;
229 grid_in.attach_triangulation(serial_source);
230
231 grid_in.read_msh(input);
232
233 // Verify the mesh was loaded properly
234 if (serial_source.n_active_cells() == 0) {
235 throw std::runtime_error("Loaded mesh contains no cells");
236 }
237
238 pcout << "Successfully loaded serial mesh with "
239 << serial_source.n_active_cells() << " cells and "
240 << serial_source.n_vertices() << " vertices" << std::endl;
241
242 // Partition the serial mesh using z-order curve
243 GridTools::partition_triangulation_zorder(n_mpi_processes, serial_source);
244
245 // Convert to fullydistributed triangulation
246 auto construction_data = TriangulationDescription::Utilities::create_description_from_triangulation(
247 serial_source, mpi_communicator,
248 TriangulationDescription::Settings::default_setting);
249
250 // Clear old DoFHandler first
251 dof_handler_source.clear();
252 // Then clear and recreate triangulation
253 source_mesh.clear();
254 source_mesh.create_triangulation(construction_data);
255
256 // Verify the distributed mesh
257 const unsigned int n_global_active_cells =
258 Utilities::MPI::sum(source_mesh.n_locally_owned_active_cells(), mpi_communicator);
259
260 if (n_global_active_cells == 0) {
261 throw std::runtime_error("Distributed mesh contains no cells");
262 }
263
264 pcout << "Successfully created distributed mesh with "
265 << n_global_active_cells << " total cells across "
266 << n_mpi_processes << " processes" << std::endl;
267
268 } catch (const std::exception& e) {
269 throw std::runtime_error("Failed to load mesh from " + mesh_file +
270 "\nError: " + e.what());
271 }
272}
273
274
275template <int dim, int spacedim>
276void MeshManager<dim, spacedim>::save_meshes(const parallel::fullydistributed::Triangulation<dim, spacedim>& source_mesh,
277 const Triangulation<dim, spacedim>& target_mesh)
278{
279 write_mesh(source_mesh,
280 mesh_directory + "/source",
281 std::vector<std::string>{"vtk", "msh"});
282
283 write_mesh(target_mesh,
284 mesh_directory + "/target",
285 std::vector<std::string>{"vtk", "msh"});
286
287 pcout << "Meshes saved in VTK and MSH formats" << std::endl;
288}
289
290template <int dim, int spacedim>
291template <typename TriangulationType>
292bool MeshManager<dim, spacedim>::write_mesh(const TriangulationType& mesh,
293 const std::string& filepath,
294 const std::vector<std::string>& formats,
295 const std::vector<double>* cell_data,
296 const std::string& data_name)
297{
298 try {
299 std::filesystem::path path(filepath);
300 std::filesystem::create_directories(path.parent_path());
301
302 GridOut grid_out;
303
304 for (const auto& format : formats) {
305 if (format == "vtk") {
306 std::ofstream out_vtk(filepath + ".vtk");
307 if (!out_vtk.is_open()) {
308 pcout << "Error: Unable to open file for writing: "
309 << filepath + ".vtk" << std::endl;
310 return false;
311 }
312 grid_out.write_vtk(mesh, out_vtk);
313 pcout << "Mesh saved to: " << filepath + ".vtk" << std::endl;
314 }
315 else if (format == "msh") {
316 // First write in default format
317 std::ofstream out_msh(filepath + ".msh");
318 if (!out_msh.is_open()) {
319 pcout << "Error: Unable to open file for writing: "
320 << filepath + ".msh" << std::endl;
321 return false;
322 }
323 grid_out.write_msh(mesh, out_msh);
324 out_msh.close();
325
326 // Convert to MSH2 format using gmsh
327 std::string cmd = "gmsh " + filepath + ".msh -format msh2 -save_all -3 -o " +
328 filepath + "_msh2.msh && mv " + filepath + "_msh2.msh " +
329 filepath + ".msh";
330 int ret = system(cmd.c_str());
331 if (ret != 0) {
332 pcout << "Error: Failed to convert mesh to MSH2 format" << std::endl;
333 return false;
334 }
335 pcout << "Mesh saved and converted to MSH2 format: " << filepath + ".msh" << std::endl;
336 }
337 else if (format == "vtu") {
338 DataOut<dim, spacedim> data_out;
339 data_out.attach_triangulation(mesh);
340
341 // Add cell data if provided
342 if (cell_data != nullptr) {
343 Assert(cell_data->size() == mesh.n_active_cells(),
344 ExcDimensionMismatch(cell_data->size(),
345 mesh.n_active_cells()));
346
347 Vector<double> cell_data_vector(cell_data->begin(), cell_data->end());
348 data_out.add_data_vector(cell_data_vector, data_name);
349 }
350
351 data_out.build_patches();
352
353 std::ofstream out_vtu(filepath + ".vtu");
354 if (!out_vtu.is_open()) {
355 pcout << "Error: Unable to open file for writing: "
356 << filepath + ".vtu" << std::endl;
357 return false;
358 }
359 data_out.write_vtu(out_vtu);
360 pcout << "Mesh saved to: " << filepath + ".vtu" << std::endl;
361 }
362 else {
363 pcout << "Warning: Unsupported format '" << format
364 << "' requested" << std::endl;
365 }
366 }
367
368 return true;
369 }
370 catch (const std::exception& e) {
371 pcout << "Error writing mesh: " << e.what() << std::endl;
372 return false;
373 }
374}
375
376template <int dim, int spacedim>
377std::vector<std::string> MeshManager<dim, spacedim>::get_mesh_hierarchy_files(const std::string& dir)
378{
379 std::vector<std::string> mesh_files;
380
381 // List all .msh files in the hierarchy directory
382 for (const auto& entry : std::filesystem::directory_iterator(dir)) {
383 if (entry.path().extension() == ".msh") {
384 mesh_files.push_back(entry.path().string());
385 }
386 }
387
388 // Sort in reverse order (coarsest to finest)
389 std::sort(mesh_files.begin(), mesh_files.end(), std::greater<std::string>());
390 return mesh_files;
391}
392
393#endif // MESH_MANAGER_TEMPLATES_H
static std::vector< std::string > get_mesh_hierarchy_files(const std::string &dir="output/data_multilevel/source_multilevel")
Get sorted list of mesh hierarchy files.
bool write_mesh(const TriangulationType &mesh, const std::string &filepath, const std::vector< std::string > &formats, const std::vector< double > *cell_data=nullptr, const std::string &data_name="cell_data")
Write mesh to file in specified formats with optional cell data.
void load_source_mesh(parallel::fullydistributed::Triangulation< dim, spacedim > &source_mesh, const std::string &source_file="")
Load source mesh from file into distributed triangulation.
void load_target_mesh(Triangulation< dim, spacedim > &target_mesh)
Load target mesh from file into serial triangulation.
MeshManager(const MPI_Comm &comm)
Constructor for MeshManager.
void generate_mesh(TriangulationType &tria, const std::string &grid_generator_function, const std::string &grid_generator_arguments, const unsigned int n_refinements, const bool use_tetrahedral_mesh)
Generate mesh using deal.II grid generator.
void save_meshes(const parallel::fullydistributed::Triangulation< dim, spacedim > &source_mesh, const Triangulation< dim, spacedim > &target_mesh)
Save source and target meshes to files.
void load_mesh_at_level(parallel::fullydistributed::Triangulation< dim, spacedim > &source_mesh, DoFHandler< dim, spacedim > &dof_handler_source, const std::string &mesh_file)
Load mesh at specific refinement level.