Skip to content

Commit 4ff6056

Browse files
authored
Merge pull request #31 from fdrmrc/fix_2d3
Fix some 2d3d tests
2 parents 707bb30 + f51dd11 commit 4ff6056

File tree

4 files changed

+283
-62
lines changed

4 files changed

+283
-62
lines changed

README.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
# Non Matching Test Suite
22

3-
Collection of C++ finite element programs testing different coupling strategies with Non Matching techniques using composite quadrature rules on mesh intersections. This is done by integrating the C++ library `CGAL` (https://www.cgal.org/) into `deal.II` (www.dealii.org). Currently, all examples require a `deal.II` version greater or equal to `9.4.2`, a C++17-compliant compiler and a `CGAL` version greater than 5.5.2 installed.
3+
C++ application consisting of finite element programs testing different coupling strategies with via non matching techniques such as using quadrature rules on mesh intersections. Part of this work builds on top of the integration of the C++ library `CGAL` (https://www.cgal.org/) into `deal.II` (www.dealii.org). Currently, a `deal.II` version greater or equal than `9.4.2`, and `CGAL` versions greater than 5.5.2 are required, along with a C++17 compliant compiler.
44

5-
![Screenshot](grids/Flower_interface.png)
5+
![Screenshot](grids/mesh_3d.png)
66

7-
## How to compile and run
8-
We provide parameter files (.prm) for test cases, allowing the user to change rhs, boundary conditions, number of refinement cycles and mesh related parameters. To compile and run, move into the desired folder (e.g. `/LagrangeMultiplier/1d2d`).
9-
10-
- Set the `DEAL_II_DIR` to the directory where you built the branch above. Alternatively, you can pass it as one of the CMake flags
7+
![Screenshot](grids/iso_contour_3D_ns.png)
118

12-
- `cmake .` , or `cmake -DDEAL_II_DIR=/your/local/path/to/deal` if you want to pass it as a flag
9+
## How to compile and run
1310

14-
- Compile with `make ` (or `make -jN`)
11+
- `mkdir build && cd build`
12+
- `cmake .` , or `cmake -DDEAL_II_DIR=/your/local/path/to/deal`
13+
- `make`, or `make -j N`, begin `N` the number of make jobs you may want to ask.
1514

16-
- Run `./lagrange_multiplier disk_parameters.prm`
1715

1816
## Using Docker image [TODO]

examples/interface_penalisation/2d3d/interface_penalisation_non_smooth_disk.cc

Lines changed: 127 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,9 @@ template <>
9191
double Solution<3>::value(const Point<3> &p,
9292
const unsigned int component) const {
9393
(void)component;
94-
// const Point<3> xc{Cx, Cy, Cz}; // center of the sphere
95-
// const double r = (p - xc).norm();
96-
// return r <= R ? 1. / R : 1. / r;
97-
return std::sin(2. * numbers::PI * p[0]) * std::sin(2. * numbers::PI * p[1]) *
98-
std::sin(2. * numbers::PI * p[2]);
94+
const Point<3> xc{Cx, Cy, Cz}; // center of the sphere
95+
const double r = (p - xc).norm();
96+
return r <= R ? 1. / R : 1. / r;
9997
}
10098

10199
template <>
@@ -120,6 +118,8 @@ template <int dim, int spacedim> class PoissonNitscheInterface {
120118
private:
121119
void generate_grids();
122120

121+
void adjust_grids();
122+
123123
void setup_system();
124124

125125
void assemble_system();
@@ -211,6 +211,112 @@ void PoissonNitscheInterface<dim, spacedim>::generate_grids() {
211211
std::make_unique<GridTools::Cache<dim, spacedim>>(embedded_triangulation);
212212
}
213213

214+
template <int dim, int spacedim>
215+
void PoissonNitscheInterface<dim, spacedim>::adjust_grids() {
216+
// Adjust grid diameters to satisfy ratio suggested by the theory.
217+
218+
std::cout << "Adjusting the grids..." << std::endl;
219+
namespace bgi = boost::geometry::index;
220+
221+
auto refine = [&]() {
222+
bool done = false;
223+
224+
double min_embedded = 1e10;
225+
double max_embedded = 0;
226+
double min_space = 1e10;
227+
double max_space = 0;
228+
229+
while (done == false) {
230+
// Bounding boxes of the space grid
231+
const auto &tree =
232+
space_cache->get_locally_owned_cell_bounding_boxes_rtree();
233+
234+
// Bounding boxes of the embedded grid
235+
const auto &embedded_tree =
236+
embedded_cache->get_cell_bounding_boxes_rtree();
237+
238+
// Let's check all cells whose bounding box contains an embedded
239+
// bounding box
240+
done = true;
241+
242+
const bool use_space = false;
243+
244+
const bool use_embedded = false;
245+
246+
AssertThrow(!(use_embedded && use_space),
247+
ExcMessage("You can't refine both the embedded and "
248+
"the space grid at the same time."));
249+
250+
for (const auto &[embedded_box, embedded_cell] : embedded_tree) {
251+
const auto &[p1, p2] = embedded_box.get_boundary_points();
252+
const auto diameter = p1.distance(p2);
253+
min_embedded = std::min(min_embedded, diameter);
254+
max_embedded = std::max(max_embedded, diameter);
255+
256+
for (const auto &[space_box, space_cell] :
257+
tree | bgi::adaptors::queried(bgi::intersects(embedded_box))) {
258+
const auto &[sp1, sp2] = space_box.get_boundary_points();
259+
const auto space_diameter = sp1.distance(sp2);
260+
min_space = std::min(min_space, space_diameter);
261+
max_space = std::max(max_space, space_diameter);
262+
263+
if (use_embedded && space_diameter < diameter) {
264+
embedded_cell->set_refine_flag();
265+
done = false;
266+
}
267+
if (use_space && diameter < space_diameter) {
268+
space_cell->set_refine_flag();
269+
done = false;
270+
}
271+
}
272+
}
273+
if (done == false) {
274+
if (use_embedded) {
275+
// Compute again the embedded displacement grid
276+
embedded_triangulation.execute_coarsening_and_refinement();
277+
}
278+
if (use_space) {
279+
// Compute again the embedded displacement grid
280+
space_triangulation.execute_coarsening_and_refinement();
281+
}
282+
}
283+
}
284+
return std::make_tuple(min_space, max_space, min_embedded, max_embedded);
285+
};
286+
287+
// Do the refinement loop once, to make sure we satisfy our criterions
288+
refine();
289+
290+
// Pre refine the space grid according to the delta refinement
291+
const bool apply_delta_refinements = true;
292+
unsigned int space_pre_refinement_cycles = 1;
293+
if (apply_delta_refinements)
294+
for (unsigned int i = 0; i < space_pre_refinement_cycles; ++i) {
295+
const auto &tree =
296+
space_cache->get_locally_owned_cell_bounding_boxes_rtree();
297+
298+
const auto &embedded_tree =
299+
embedded_cache->get_cell_bounding_boxes_rtree();
300+
301+
for (const auto &[embedded_box, embedded_cell] : embedded_tree)
302+
for (const auto &[space_box, space_cell] :
303+
tree | bgi::adaptors::queried(bgi::intersects(embedded_box)))
304+
space_cell->set_refine_flag();
305+
space_triangulation.execute_coarsening_and_refinement();
306+
307+
// Make sure again we satisfy our criterion after the space refinement
308+
refine();
309+
}
310+
311+
// Check once again we satisfy our criterion, and record min/max
312+
const auto [sm, sM, em, eM] = refine();
313+
314+
std::cout << "Space local min/max diameters : " << sm << "/" << sM
315+
<< std::endl
316+
<< "Embedded space min/max diameters: " << em << "/" << eM
317+
<< std::endl;
318+
}
319+
214320
template <int dim, int spacedim>
215321
void PoissonNitscheInterface<dim, spacedim>::setup_system() {
216322
TimerOutput::Scope timer_section(timer, "Setup system");
@@ -357,15 +463,18 @@ template <int dim, int spacedim>
357463
void PoissonNitscheInterface<dim, spacedim>::output_results(
358464
const unsigned cycle) const {
359465
TimerOutput::Scope timer_section(timer, "Output results");
360-
// std::cout << "Output results" << std::endl;
361-
data_out.clear();
362-
data_out.attach_dof_handler(space_dh);
363-
data_out.add_data_vector(solution, "solution");
364-
data_out.build_patches();
365-
std::ofstream output("solution_nitsche" + std::to_string(dim) +
366-
std::to_string(spacedim) + std::to_string(cycle) +
367-
".vtu");
368-
data_out.write_vtu(output);
466+
467+
if (cycle < 2) {
468+
data_out.clear();
469+
data_out.attach_dof_handler(space_dh);
470+
data_out.add_data_vector(solution, "solution");
471+
data_out.build_patches();
472+
std::ofstream output("solution_nitsche" + std::to_string(dim) +
473+
std::to_string(spacedim) + std::to_string(cycle) +
474+
".vtu");
475+
data_out.write_vtu(output);
476+
}
477+
369478
{
370479
Vector<double> difference_per_cell(space_triangulation.n_active_cells());
371480
VectorTools::integrate_difference(
@@ -385,19 +494,11 @@ void PoissonNitscheInterface<dim, spacedim>::output_results(
385494

386495
convergence_table.add_value("cycle", cycle);
387496
convergence_table.add_value("cells", space_triangulation.n_active_cells());
388-
convergence_table.add_value("dofs", space_dh.n_dofs());
497+
convergence_table.add_value("dofs", space_dh.n_dofs() -
498+
space_constraints.n_constraints());
389499
convergence_table.add_value("L2", L2_error);
390500
convergence_table.add_value("H1", H1_error);
391501
}
392-
393-
{
394-
if (cycle == 3) {
395-
std::ofstream output_test_space("space_grid_cycle3.vtk");
396-
GridOut().write_vtk(space_triangulation, output_test_space);
397-
std::ofstream output_test_embedded("embedded_grid_cycle3.vtk");
398-
GridOut().write_vtk(embedded_triangulation, output_test_embedded);
399-
}
400-
}
401502
}
402503

403504
// The run() method here differs only in the call to
@@ -407,7 +508,8 @@ void PoissonNitscheInterface<dim, spacedim>::run() {
407508
generate_grids();
408509
for (unsigned int cycle = 0; cycle < n_refinement_cycles; ++cycle) {
409510
std::cout << "Cycle: " << cycle << std::endl;
410-
511+
if (cycle == 0u)
512+
adjust_grids();
411513
// Compute all the things we need to assemble the Nitsche's
412514
// contributions, namely the two cached triangulations and a degree to
413515
// integrate over the intersections.

examples/interface_penalisation/2d3d/interface_penalisation_smooth_disk.cc

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ template <int dim, int spacedim> class PoissonNitscheInterface {
124124
private:
125125
void generate_grids();
126126

127+
void adjust_grids();
128+
127129
void setup_system();
128130

129131
void assemble_system();
@@ -216,6 +218,112 @@ void PoissonNitscheInterface<dim, spacedim>::generate_grids() {
216218
std::make_unique<GridTools::Cache<dim, spacedim>>(embedded_triangulation);
217219
}
218220

221+
template <int dim, int spacedim>
222+
void PoissonNitscheInterface<dim, spacedim>::adjust_grids() {
223+
// Adjust grid diameters to satisfy ratio suggested by the theory.
224+
225+
std::cout << "Adjusting the grids..." << std::endl;
226+
namespace bgi = boost::geometry::index;
227+
228+
auto refine = [&]() {
229+
bool done = false;
230+
231+
double min_embedded = 1e10;
232+
double max_embedded = 0;
233+
double min_space = 1e10;
234+
double max_space = 0;
235+
236+
while (done == false) {
237+
// Bounding boxes of the space grid
238+
const auto &tree =
239+
space_cache->get_locally_owned_cell_bounding_boxes_rtree();
240+
241+
// Bounding boxes of the embedded grid
242+
const auto &embedded_tree =
243+
embedded_cache->get_cell_bounding_boxes_rtree();
244+
245+
// Let's check all cells whose bounding box contains an embedded
246+
// bounding box
247+
done = true;
248+
249+
const bool use_space = false;
250+
251+
const bool use_embedded = false;
252+
253+
AssertThrow(!(use_embedded && use_space),
254+
ExcMessage("You can't refine both the embedded and "
255+
"the space grid at the same time."));
256+
257+
for (const auto &[embedded_box, embedded_cell] : embedded_tree) {
258+
const auto &[p1, p2] = embedded_box.get_boundary_points();
259+
const auto diameter = p1.distance(p2);
260+
min_embedded = std::min(min_embedded, diameter);
261+
max_embedded = std::max(max_embedded, diameter);
262+
263+
for (const auto &[space_box, space_cell] :
264+
tree | bgi::adaptors::queried(bgi::intersects(embedded_box))) {
265+
const auto &[sp1, sp2] = space_box.get_boundary_points();
266+
const auto space_diameter = sp1.distance(sp2);
267+
min_space = std::min(min_space, space_diameter);
268+
max_space = std::max(max_space, space_diameter);
269+
270+
if (use_embedded && space_diameter < diameter) {
271+
embedded_cell->set_refine_flag();
272+
done = false;
273+
}
274+
if (use_space && diameter < space_diameter) {
275+
space_cell->set_refine_flag();
276+
done = false;
277+
}
278+
}
279+
}
280+
if (done == false) {
281+
if (use_embedded) {
282+
// Compute again the embedded displacement grid
283+
embedded_triangulation.execute_coarsening_and_refinement();
284+
}
285+
if (use_space) {
286+
// Compute again the embedded displacement grid
287+
space_triangulation.execute_coarsening_and_refinement();
288+
}
289+
}
290+
}
291+
return std::make_tuple(min_space, max_space, min_embedded, max_embedded);
292+
};
293+
294+
// Do the refinement loop once, to make sure we satisfy our criterions
295+
refine();
296+
297+
// Pre refine the space grid according to the delta refinement
298+
const bool apply_delta_refinements = true;
299+
unsigned int space_pre_refinement_cycles = 1;
300+
if (apply_delta_refinements)
301+
for (unsigned int i = 0; i < space_pre_refinement_cycles; ++i) {
302+
const auto &tree =
303+
space_cache->get_locally_owned_cell_bounding_boxes_rtree();
304+
305+
const auto &embedded_tree =
306+
embedded_cache->get_cell_bounding_boxes_rtree();
307+
308+
for (const auto &[embedded_box, embedded_cell] : embedded_tree)
309+
for (const auto &[space_box, space_cell] :
310+
tree | bgi::adaptors::queried(bgi::intersects(embedded_box)))
311+
space_cell->set_refine_flag();
312+
space_triangulation.execute_coarsening_and_refinement();
313+
314+
// Make sure again we satisfy our criterion after the space refinement
315+
refine();
316+
}
317+
318+
// Check once again we satisfy our criterion, and record min/max
319+
const auto [sm, sM, em, eM] = refine();
320+
321+
std::cout << "Space local min/max diameters : " << sm << "/" << sM
322+
<< std::endl
323+
<< "Embedded space min/max diameters: " << em << "/" << eM
324+
<< std::endl;
325+
}
326+
219327
template <int dim, int spacedim>
220328
void PoissonNitscheInterface<dim, spacedim>::setup_system() {
221329
TimerOutput::Scope timer_section(timer, "Setup system");
@@ -388,7 +496,8 @@ void PoissonNitscheInterface<dim, spacedim>::output_results(
388496

389497
convergence_table.add_value("cycle", cycle);
390498
convergence_table.add_value("cells", space_triangulation.n_active_cells());
391-
convergence_table.add_value("dofs", space_dh.n_dofs());
499+
convergence_table.add_value("dofs", space_dh.n_dofs() -
500+
space_constraints.n_constraints());
392501
convergence_table.add_value("L2", L2_error);
393502
convergence_table.add_value("H1", H1_error);
394503
}
@@ -411,6 +520,9 @@ void PoissonNitscheInterface<dim, spacedim>::run() {
411520
for (unsigned int cycle = 0; cycle < n_refinement_cycles; ++cycle) {
412521
std::cout << "Cycle: " << cycle << std::endl;
413522

523+
if (cycle == 0u) {
524+
adjust_grids();
525+
}
414526
// Compute all the things we need to assemble the Nitsche's
415527
// contributions, namely the two cached triangulations and a degree to
416528
// integrate over the intersections.
@@ -437,7 +549,6 @@ void PoissonNitscheInterface<dim, spacedim>::run() {
437549
solve();
438550
}
439551

440-
// error_table.error_from_exact(space_dh, solution, exact_solution);
441552
output_results(cycle);
442553

443554
if (cycle < n_refinement_cycles - 1) {

0 commit comments

Comments
 (0)