deal.II version 9.8.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
coupling.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2018 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
14#include <deal.II/base/point.h>
15#include <deal.II/base/tensor.h>
16
19
21
25
34
36
37#include <complex>
38#include <limits>
39
41namespace NonMatching
42{
43 namespace internal
44 {
62 template <int dim0, int dim1, int spacedim>
63 std::pair<std::vector<Point<spacedim>>, std::vector<unsigned int>>
66 const DoFHandler<dim1, spacedim> &immersed_dh,
67 const Quadrature<dim1> &quad,
68 const Mapping<dim1, spacedim> &immersed_mapping,
69 const bool tria_is_parallel)
70 {
71 const auto &immersed_fe = immersed_dh.get_fe();
72 std::vector<Point<spacedim>> points_over_local_cells;
73 // Keep track of which cells we actually used
74 std::vector<unsigned int> used_cells_ids;
75 {
76 FEValues<dim1, spacedim> fe_v(immersed_mapping,
77 immersed_fe,
78 quad,
80 unsigned int cell_id = 0;
81 for (const auto &cell : immersed_dh.active_cell_iterators())
82 {
83 bool use_cell = false;
84 if (tria_is_parallel)
85 {
86 const auto bbox = cell->bounding_box();
87 std::vector<std::pair<
90 out_vals;
92 boost::geometry::index::intersects(bbox),
93 std::back_inserter(out_vals));
94 // Each bounding box corresponds to an active cell
95 // of the embedding triangulation: we now check if
96 // the current cell, of the embedded triangulation,
97 // overlaps a locally owned cell of the embedding one
98 for (const auto &bbox_it : out_vals)
99 if (bbox_it.second->is_locally_owned())
100 {
101 use_cell = true;
102 used_cells_ids.emplace_back(cell_id);
103 break;
104 }
105 }
106 else
107 // for sequential triangulations, simply use all cells
108 use_cell = true;
109
110 if (use_cell)
111 {
112 // Reinitialize the cell and the fe_values
113 fe_v.reinit(cell);
114 const std::vector<Point<spacedim>> &x_points =
115 fe_v.get_quadrature_points();
116
117 // Insert the points to the vector
118 points_over_local_cells.insert(points_over_local_cells.end(),
119 x_points.begin(),
120 x_points.end());
121 }
122 ++cell_id;
123 }
124 }
125 return {std::move(points_over_local_cells), std::move(used_cells_ids)};
126 }
127
128
135 template <int dim0, int dim1, int spacedim>
136 std::pair<std::vector<unsigned int>, std::vector<unsigned int>>
138 const ComponentMask &comps1,
141 {
142 // Take care of components
143 const ComponentMask mask0 =
144 (comps0.size() == 0 ? ComponentMask(fe0.n_components(), true) : comps0);
145
146 const ComponentMask mask1 =
147 (comps1.size() == 0 ? ComponentMask(fe1.n_components(), true) : comps1);
148
149 AssertDimension(mask0.size(), fe0.n_components());
150 AssertDimension(mask1.size(), fe1.n_components());
151
152 // Global to local indices
153 std::vector<unsigned int> gtl0(fe0.n_components(),
155 std::vector<unsigned int> gtl1(fe1.n_components(),
157
158 for (unsigned int i = 0, j = 0; i < gtl0.size(); ++i)
159 if (mask0[i])
160 gtl0[i] = j++;
161
162 for (unsigned int i = 0, j = 0; i < gtl1.size(); ++i)
163 if (mask1[i])
164 gtl1[i] = j++;
165 return {gtl0, gtl1};
166 }
167 } // namespace internal
168
169 template <int dim0, int dim1, int spacedim, typename number>
170 void
172 const DoFHandler<dim0, spacedim> &space_dh,
173 const DoFHandler<dim1, spacedim> &immersed_dh,
174 const Quadrature<dim1> &quad,
175 SparsityPatternBase &sparsity,
176 const AffineConstraints<number> &constraints,
177 const ComponentMask &space_comps,
178 const ComponentMask &immersed_comps,
179 const Mapping<dim0, spacedim> &space_mapping,
180 const Mapping<dim1, spacedim> &immersed_mapping,
181 const AffineConstraints<number> &immersed_constraints)
182 {
184 space_mapping);
186 space_dh,
187 immersed_dh,
188 quad,
189 sparsity,
190 constraints,
191 space_comps,
192 immersed_comps,
193 immersed_mapping,
194 immersed_constraints);
195 }
196
197
198
199 template <int dim0, int dim1, int spacedim, typename number>
200 void
203 const DoFHandler<dim0, spacedim> &space_dh,
204 const DoFHandler<dim1, spacedim> &immersed_dh,
205 const Quadrature<dim1> &quad,
206 SparsityPatternBase &sparsity,
207 const AffineConstraints<number> &constraints,
208 const ComponentMask &space_comps,
209 const ComponentMask &immersed_comps,
210 const Mapping<dim1, spacedim> &immersed_mapping,
211 const AffineConstraints<number> &immersed_constraints)
212 {
213 AssertDimension(sparsity.n_rows(), space_dh.n_dofs());
214 AssertDimension(sparsity.n_cols(), immersed_dh.n_dofs());
215 Assert(dim1 <= dim0,
216 ExcMessage("This function can only work if dim1 <= dim0"));
217 Assert((dynamic_cast<
219 &immersed_dh.get_triangulation()) == nullptr),
221
222 const bool tria_is_parallel =
223 (dynamic_cast<const parallel::TriangulationBase<dim0, spacedim> *>(
224 &space_dh.get_triangulation()) != nullptr);
225 const auto &space_fe = space_dh.get_fe();
226 const auto &immersed_fe = immersed_dh.get_fe();
227
228 // Dof indices
229 std::vector<types::global_dof_index> dofs(immersed_fe.n_dofs_per_cell());
230 std::vector<types::global_dof_index> odofs(space_fe.n_dofs_per_cell());
231
232 // Take care of components
233 const ComponentMask space_c =
234 (space_comps.size() == 0 ? ComponentMask(space_fe.n_components(), true) :
235 space_comps);
236
237 const ComponentMask immersed_c =
238 (immersed_comps.size() == 0 ?
239 ComponentMask(immersed_fe.n_components(), true) :
240 immersed_comps);
241
242 AssertDimension(space_c.size(), space_fe.n_components());
243 AssertDimension(immersed_c.size(), immersed_fe.n_components());
244
245 // Global to local indices
246 std::vector<unsigned int> space_gtl(space_fe.n_components(),
248 std::vector<unsigned int> immersed_gtl(immersed_fe.n_components(),
250
251 for (unsigned int i = 0, j = 0; i < space_gtl.size(); ++i)
252 if (space_c[i])
253 space_gtl[i] = j++;
254
255 for (unsigned int i = 0, j = 0; i < immersed_gtl.size(); ++i)
256 if (immersed_c[i])
257 immersed_gtl[i] = j++;
258
259 const unsigned int n_q_points = quad.size();
260 const unsigned int n_active_c =
261 immersed_dh.get_triangulation().n_active_cells();
262
263 const auto qpoints_cells_data = internal::qpoints_over_locally_owned_cells(
264 cache, immersed_dh, quad, immersed_mapping, tria_is_parallel);
265
266 const auto &points_over_local_cells = std::get<0>(qpoints_cells_data);
267 const auto &used_cells_ids = std::get<1>(qpoints_cells_data);
268
269 // [TODO]: when the add_entries_local_to_global below will implement
270 // the version with the dof_mask, this should be uncommented.
271 //
272 // // Construct a dof_mask, used to distribute entries to the sparsity
273 // able< 2, bool > dof_mask(space_fe.n_dofs_per_cell(),
274 // immersed_fe.n_dofs_per_cell());
275 // of_mask.fill(false);
276 // or (unsigned int i=0; i<space_fe.n_dofs_per_cell(); ++i)
277 // {
278 // const auto comp_i = space_fe.system_to_component_index(i).first;
279 // if (space_gtl[comp_i] != numbers::invalid_unsigned_int)
280 // for (unsigned int j=0; j<immersed_fe.n_dofs_per_cell(); ++j)
281 // {
282 // const auto comp_j =
283 // immersed_fe.system_to_component_index(j).first; if
284 // (immersed_gtl[comp_j] == space_gtl[comp_i])
285 // dof_mask(i,j) = true;
286 // }
287 // }
288
289
290 // Get a list of outer cells, qpoints and maps.
291 const auto cpm =
292 GridTools::compute_point_locations(cache, points_over_local_cells);
293 const auto &all_cells = std::get<0>(cpm);
294 const auto &maps = std::get<2>(cpm);
295
296 std::vector<
297 std::set<typename Triangulation<dim0, spacedim>::active_cell_iterator>>
298 cell_sets(n_active_c);
299
300 for (unsigned int i = 0; i < maps.size(); ++i)
301 {
302 // Quadrature points should be reasonably clustered:
303 // the following index keeps track of the last id
304 // where the current cell was inserted
305 unsigned int last_id = std::numeric_limits<unsigned int>::max();
306 unsigned int cell_id;
307 for (const unsigned int idx : maps[i])
308 {
309 // Find in which cell of immersed triangulation the point lies
310 if (tria_is_parallel)
311 cell_id = used_cells_ids[idx / n_q_points];
312 else
313 cell_id = idx / n_q_points;
314
315 if (last_id != cell_id)
316 {
317 cell_sets[cell_id].insert(all_cells[i]);
318 last_id = cell_id;
319 }
320 }
321 }
322
323 // Now we run on each cell of the immersed
324 // and build the sparsity
325 unsigned int i = 0;
326 for (const auto &cell : immersed_dh.active_cell_iterators())
327 {
328 // Reinitialize the cell
329 cell->get_dof_indices(dofs);
330
331 // List of outer cells
332 const auto &cells = cell_sets[i];
333
334 for (const auto &cell_c : cells)
335 {
336 // Get the ones in the current outer cell
337 typename DoFHandler<dim0, spacedim>::cell_iterator ocell(*cell_c,
338 &space_dh);
339 // Make sure we act only on locally_owned cells
340 if (ocell->is_locally_owned())
341 {
342 ocell->get_dof_indices(odofs);
343 // [TODO]: When the following function will be implemented
344 // for the case of non-trivial dof_mask, we should
345 // uncomment the missing part.
346 constraints.add_entries_local_to_global(
347 odofs,
348 immersed_constraints,
349 dofs,
350 sparsity); //, true, dof_mask);
351 }
352 }
353 ++i;
354 }
355 }
356
357
358
359 template <int dim0, int dim1, int spacedim, typename Matrix>
360 void
362 const DoFHandler<dim0, spacedim> &space_dh,
363 const DoFHandler<dim1, spacedim> &immersed_dh,
364 const Quadrature<dim1> &quad,
365 Matrix &matrix,
367 const ComponentMask &space_comps,
368 const ComponentMask &immersed_comps,
369 const Mapping<dim0, spacedim> &space_mapping,
370 const Mapping<dim1, spacedim> &immersed_mapping,
371 const AffineConstraints<typename Matrix::value_type> &immersed_constraints)
372 {
374 space_mapping);
376 space_dh,
377 immersed_dh,
378 quad,
379 matrix,
380 constraints,
381 space_comps,
382 immersed_comps,
383 immersed_mapping,
384 immersed_constraints);
385 }
386
387
388
389 template <int dim0, int dim1, int spacedim, typename Matrix>
390 void
393 const DoFHandler<dim0, spacedim> &space_dh,
394 const DoFHandler<dim1, spacedim> &immersed_dh,
395 const Quadrature<dim1> &quad,
396 Matrix &matrix,
398 const ComponentMask &space_comps,
399 const ComponentMask &immersed_comps,
400 const Mapping<dim1, spacedim> &immersed_mapping,
401 const AffineConstraints<typename Matrix::value_type> &immersed_constraints)
402 {
403 AssertDimension(matrix.m(), space_dh.n_dofs());
404 AssertDimension(matrix.n(), immersed_dh.n_dofs());
405 Assert(dim1 <= dim0,
406 ExcMessage("This function can only work if dim1 <= dim0"));
407 Assert((dynamic_cast<
409 &immersed_dh.get_triangulation()) == nullptr),
411
412 const bool tria_is_parallel =
413 (dynamic_cast<const parallel::TriangulationBase<dim0, spacedim> *>(
414 &space_dh.get_triangulation()) != nullptr);
415
416 const auto &space_fe = space_dh.get_fe();
417 const auto &immersed_fe = immersed_dh.get_fe();
418
419 // Dof indices
420 std::vector<types::global_dof_index> dofs(immersed_fe.n_dofs_per_cell());
421 std::vector<types::global_dof_index> odofs(space_fe.n_dofs_per_cell());
422
423 // Take care of components
424 const ComponentMask space_c =
425 (space_comps.size() == 0 ? ComponentMask(space_fe.n_components(), true) :
426 space_comps);
427
428 const ComponentMask immersed_c =
429 (immersed_comps.size() == 0 ?
430 ComponentMask(immersed_fe.n_components(), true) :
431 immersed_comps);
432
433 AssertDimension(space_c.size(), space_fe.n_components());
434 AssertDimension(immersed_c.size(), immersed_fe.n_components());
435
436 std::vector<unsigned int> space_gtl(space_fe.n_components(),
438 std::vector<unsigned int> immersed_gtl(immersed_fe.n_components(),
440
441 for (unsigned int i = 0, j = 0; i < space_gtl.size(); ++i)
442 if (space_c[i])
443 space_gtl[i] = j++;
444
445 for (unsigned int i = 0, j = 0; i < immersed_gtl.size(); ++i)
446 if (immersed_c[i])
447 immersed_gtl[i] = j++;
448
450 space_dh.get_fe().n_dofs_per_cell(),
451 immersed_dh.get_fe().n_dofs_per_cell());
452
453 FEValues<dim1, spacedim> fe_v(immersed_mapping,
454 immersed_dh.get_fe(),
455 quad,
458
459 const unsigned int n_q_points = quad.size();
460 const unsigned int n_active_c =
461 immersed_dh.get_triangulation().n_active_cells();
462
463 const auto used_cells_data = internal::qpoints_over_locally_owned_cells(
464 cache, immersed_dh, quad, immersed_mapping, tria_is_parallel);
465
466 const auto &points_over_local_cells = std::get<0>(used_cells_data);
467 const auto &used_cells_ids = std::get<1>(used_cells_data);
468
469 // Get a list of outer cells, qpoints and maps.
470 const auto cpm =
471 GridTools::compute_point_locations(cache, points_over_local_cells);
472 const auto &all_cells = std::get<0>(cpm);
473 const auto &all_qpoints = std::get<1>(cpm);
474 const auto &all_maps = std::get<2>(cpm);
475
476 std::vector<
477 std::vector<typename Triangulation<dim0, spacedim>::active_cell_iterator>>
478 cell_container(n_active_c);
479 std::vector<std::vector<std::vector<Point<dim0>>>> qpoints_container(
480 n_active_c);
481 std::vector<std::vector<std::vector<unsigned int>>> maps_container(
482 n_active_c);
483
484 // Cycle over all cells of underling mesh found
485 // call it omesh, elaborating the output
486 for (unsigned int o = 0; o < all_cells.size(); ++o)
487 {
488 for (unsigned int j = 0; j < all_maps[o].size(); ++j)
489 {
490 // Find the index of the "owner" cell and qpoint
491 // with regard to the immersed mesh
492 // Find in which cell of immersed triangulation the point lies
493 unsigned int cell_id;
494 if (tria_is_parallel)
495 cell_id = used_cells_ids[all_maps[o][j] / n_q_points];
496 else
497 cell_id = all_maps[o][j] / n_q_points;
498
499 const unsigned int n_pt = all_maps[o][j] % n_q_points;
500
501 // If there are no cells, we just add our data
502 if (cell_container[cell_id].empty())
503 {
504 cell_container[cell_id].emplace_back(all_cells[o]);
505 qpoints_container[cell_id].emplace_back(
506 std::vector<Point<dim0>>{all_qpoints[o][j]});
507 maps_container[cell_id].emplace_back(
508 std::vector<unsigned int>{n_pt});
509 }
510 // If there are already cells, we begin by looking
511 // at the last inserted cell, which is more likely:
512 else if (cell_container[cell_id].back() == all_cells[o])
513 {
514 qpoints_container[cell_id].back().emplace_back(
515 all_qpoints[o][j]);
516 maps_container[cell_id].back().emplace_back(n_pt);
517 }
518 else
519 {
520 // We don't need to check the last element
521 const auto cell_p = std::find(cell_container[cell_id].begin(),
522 cell_container[cell_id].end() - 1,
523 all_cells[o]);
524
525 if (cell_p == cell_container[cell_id].end() - 1)
526 {
527 cell_container[cell_id].emplace_back(all_cells[o]);
528 qpoints_container[cell_id].emplace_back(
529 std::vector<Point<dim0>>{all_qpoints[o][j]});
530 maps_container[cell_id].emplace_back(
531 std::vector<unsigned int>{n_pt});
532 }
533 else
534 {
535 const unsigned int pos =
536 cell_p - cell_container[cell_id].begin();
537 qpoints_container[cell_id][pos].emplace_back(
538 all_qpoints[o][j]);
539 maps_container[cell_id][pos].emplace_back(n_pt);
540 }
541 }
542 }
543 }
544
546 cell = immersed_dh.begin_active(),
547 endc = immersed_dh.end();
548
549 for (unsigned int j = 0; cell != endc; ++cell, ++j)
550 {
551 // Reinitialize the cell and the fe_values
552 fe_v.reinit(cell);
553 cell->get_dof_indices(dofs);
554
555 // Get a list of outer cells, qpoints and maps.
556 const auto &cells = cell_container[j];
557 const auto &qpoints = qpoints_container[j];
558 const auto &maps = maps_container[j];
559
560 for (unsigned int c = 0; c < cells.size(); ++c)
561 {
562 // Get the ones in the current outer cell
564 *cells[c], &space_dh);
565 // Make sure we act only on locally_owned cells
566 if (ocell->is_locally_owned())
567 {
568 const std::vector<Point<dim0>> &qps = qpoints[c];
569 const std::vector<unsigned int> &ids = maps[c];
570
572 space_dh.get_fe(),
573 qps,
575 o_fe_v.reinit(ocell);
576 ocell->get_dof_indices(odofs);
577
578 // Reset the matrices.
579 cell_matrix = typename Matrix::value_type();
580
581 for (unsigned int i = 0;
582 i < space_dh.get_fe().n_dofs_per_cell();
583 ++i)
584 {
585 const auto comp_i =
586 space_dh.get_fe().system_to_component_index(i).first;
587 if (space_gtl[comp_i] != numbers::invalid_unsigned_int)
588 for (unsigned int j = 0;
589 j < immersed_dh.get_fe().n_dofs_per_cell();
590 ++j)
591 {
592 const auto comp_j = immersed_dh.get_fe()
594 .first;
595 if (space_gtl[comp_i] == immersed_gtl[comp_j])
596 for (unsigned int oq = 0;
597 oq < o_fe_v.n_quadrature_points;
598 ++oq)
599 {
600 // Get the corresponding q point
601 const unsigned int q = ids[oq];
602
603 cell_matrix(i, j) +=
604 (fe_v.shape_value(j, q) *
605 o_fe_v.shape_value(i, oq) * fe_v.JxW(q));
606 }
607 }
608 }
609
610 // Now assemble the matrices
611 constraints.distribute_local_to_global(
612 cell_matrix, odofs, immersed_constraints, dofs, matrix);
613 }
614 }
615 }
616 }
617
618 template <int dim0, int dim1, int spacedim, typename Number>
619 void
621 const double &epsilon,
626 const Quadrature<dim1> &quad,
627 SparsityPatternBase &sparsity,
628 const AffineConstraints<Number> &constraints0,
629 const ComponentMask &comps0,
630 const ComponentMask &comps1)
631 {
632 if (epsilon == 0.0)
633 {
634 Assert(dim1 <= dim0,
635 ExcMessage("When epsilon is zero, you can only "
636 "call this function with dim1 <= dim0."));
638 dh0,
639 dh1,
640 quad,
641 sparsity,
642 constraints0,
643 comps0,
644 comps1,
645 cache1.get_mapping());
646 return;
647 }
648 AssertDimension(sparsity.n_rows(), dh0.n_dofs());
649 AssertDimension(sparsity.n_cols(), dh1.n_dofs());
650
651 const bool zero_is_distributed =
653 *>(&dh0.get_triangulation()) != nullptr);
654 const bool one_is_distributed =
656 *>(&dh1.get_triangulation()) != nullptr);
657
658 // We bail out if both are distributed triangulations
659 Assert(!zero_is_distributed || !one_is_distributed, ExcNotImplemented());
660
661 // If we can loop on both, we decide where to make the outer loop according
662 // to the size of the triangulation. The reasoning is the following:
663 // - cost for accessing the tree: log(N)
664 // - cost for computing the intersection for each of the outer loop cells: M
665 // Total cost (besides the setup) is: M log(N)
666 // If we can, make sure M is the smaller number of the two.
667 const bool outer_loop_on_zero =
668 (zero_is_distributed && !one_is_distributed) ||
671
672 const auto &fe0 = dh0.get_fe();
673 const auto &fe1 = dh1.get_fe();
674
675 // Dof indices
676 std::vector<types::global_dof_index> dofs0(fe0.n_dofs_per_cell());
677 std::vector<types::global_dof_index> dofs1(fe1.n_dofs_per_cell());
678
679 if (outer_loop_on_zero)
680 {
681 Assert(one_is_distributed == false, ExcInternalError());
682
683 const auto &tree1 = cache1.get_cell_bounding_boxes_rtree();
684
685 std::vector<std::pair<
688 intersection;
689
690 for (const auto &cell0 :
692 {
693 intersection.resize(0);
695 cache0.get_mapping().get_bounding_box(cell0);
696 box0.extend(epsilon);
697 boost::geometry::index::query(tree1,
698 boost::geometry::index::intersects(
699 box0),
700 std::back_inserter(intersection));
701 if (!intersection.empty())
702 {
703 cell0->get_dof_indices(dofs0);
704 for (const auto &entry : intersection)
705 {
707 *entry.second, &dh1);
708 cell1->get_dof_indices(dofs1);
709 constraints0.add_entries_local_to_global(dofs0,
710 dofs1,
711 sparsity);
712 }
713 }
714 }
715 }
716 else
717 {
718 Assert(zero_is_distributed == false, ExcInternalError());
719 const auto &tree0 = cache0.get_cell_bounding_boxes_rtree();
720
721 std::vector<std::pair<
724 intersection;
725
726 for (const auto &cell1 :
728 {
729 intersection.resize(0);
731 cache1.get_mapping().get_bounding_box(cell1);
732 box1.extend(epsilon);
733 boost::geometry::index::query(tree0,
734 boost::geometry::index::intersects(
735 box1),
736 std::back_inserter(intersection));
737 if (!intersection.empty())
738 {
739 cell1->get_dof_indices(dofs1);
740 for (const auto &entry : intersection)
741 {
743 *entry.second, &dh0);
744 cell0->get_dof_indices(dofs0);
745 constraints0.add_entries_local_to_global(dofs0,
746 dofs1,
747 sparsity);
748 }
749 }
750 }
751 }
752 }
753
754
755
756 template <int dim0, int dim1, int spacedim, typename Matrix>
757 void
760 const double &epsilon,
765 const Quadrature<dim0> &quadrature0,
766 const Quadrature<dim1> &quadrature1,
767 Matrix &matrix,
769 const ComponentMask &comps0,
770 const ComponentMask &comps1)
771 {
772 if (epsilon == 0)
773 {
774 Assert(dim1 <= dim0,
775 ExcMessage("When epsilon is zero, you can only "
776 "call this function with dim1 <= dim0."));
778 dh0,
779 dh1,
780 quadrature1,
781 matrix,
782 constraints0,
783 comps0,
784 comps1,
785 cache1.get_mapping());
786 return;
787 }
788
789 AssertDimension(matrix.m(), dh0.n_dofs());
790 AssertDimension(matrix.n(), dh1.n_dofs());
791
792 const bool zero_is_distributed =
794 *>(&dh0.get_triangulation()) != nullptr);
795 const bool one_is_distributed =
797 *>(&dh1.get_triangulation()) != nullptr);
798
799 // We bail out if both are distributed triangulations
800 Assert(!zero_is_distributed || !one_is_distributed, ExcNotImplemented());
801
802 // If we can loop on both, we decide where to make the outer loop according
803 // to the size of the triangulation. The reasoning is the following:
804 // - cost for accessing the tree: log(N)
805 // - cost for computing the intersection for each of the outer loop cells: M
806 // Total cost (besides the setup) is: M log(N)
807 // If we can, make sure M is the smaller number of the two.
808 const bool outer_loop_on_zero =
809 (zero_is_distributed && !one_is_distributed) ||
812
813 const auto &fe0 = dh0.get_fe();
814 const auto &fe1 = dh1.get_fe();
815
817 fe0,
818 quadrature0,
821
823 fe1,
824 quadrature1,
827
828 // Dof indices
829 std::vector<types::global_dof_index> dofs0(fe0.n_dofs_per_cell());
830 std::vector<types::global_dof_index> dofs1(fe1.n_dofs_per_cell());
831
832 // Local Matrix
833 FullMatrix<typename Matrix::value_type> cell_matrix(fe0.n_dofs_per_cell(),
834 fe1.n_dofs_per_cell());
835
836 // Global to local indices
837 const auto p =
838 internal::compute_components_coupling(comps0, comps1, fe0, fe1);
839 const auto &gtl0 = p.first;
840 const auto &gtl1 = p.second;
841
842 kernel.set_radius(epsilon);
843 std::vector<double> kernel_values(quadrature1.size());
844
845 auto assemble_one_pair = [&]() {
846 cell_matrix = 0;
847 for (unsigned int q0 = 0; q0 < quadrature0.size(); ++q0)
848 {
849 kernel.set_center(fev0.quadrature_point(q0));
850 kernel.value_list(fev1.get_quadrature_points(), kernel_values);
851 for (unsigned int j = 0; j < fe1.n_dofs_per_cell(); ++j)
852 {
853 const auto comp_j = fe1.system_to_component_index(j).first;
854
855 // First compute the part of the integral that does not
856 // depend on i
857 typename Matrix::value_type sum_q1 = {};
858 for (unsigned int q1 = 0; q1 < quadrature1.size(); ++q1)
859 sum_q1 +=
860 fev1.shape_value(j, q1) * kernel_values[q1] * fev1.JxW(q1);
861 sum_q1 *= fev0.JxW(q0);
862
863 // Now compute the main integral with the sum over q1 already
864 // completed - this gives a cubic complexity as usual rather
865 // than a quartic one with naive loops
866 for (unsigned int i = 0; i < fe0.n_dofs_per_cell(); ++i)
867 {
868 const auto comp_i = fe0.system_to_component_index(i).first;
869 if (gtl0[comp_i] != numbers::invalid_unsigned_int &&
870 gtl1[comp_j] == gtl0[comp_i])
871 cell_matrix(i, j) += fev0.shape_value(i, q0) * sum_q1;
872 }
873 }
874 }
875
876 constraints0.distribute_local_to_global(cell_matrix,
877 dofs0,
878 dofs1,
879 matrix);
880 };
881
882 if (outer_loop_on_zero)
883 {
884 Assert(one_is_distributed == false, ExcInternalError());
885
886 const auto &tree1 = cache1.get_cell_bounding_boxes_rtree();
887
888 std::vector<std::pair<
891 intersection;
892
893 for (const auto &cell0 :
895 {
896 intersection.resize(0);
898 cache0.get_mapping().get_bounding_box(cell0);
899 box0.extend(epsilon);
900 boost::geometry::index::query(tree1,
901 boost::geometry::index::intersects(
902 box0),
903 std::back_inserter(intersection));
904 if (!intersection.empty())
905 {
906 cell0->get_dof_indices(dofs0);
907 fev0.reinit(cell0);
908 for (const auto &entry : intersection)
909 {
911 *entry.second, &dh1);
912 cell1->get_dof_indices(dofs1);
913 fev1.reinit(cell1);
914 assemble_one_pair();
915 }
916 }
917 }
918 }
919 else
920 {
921 Assert(zero_is_distributed == false, ExcInternalError());
922 const auto &tree0 = cache0.get_cell_bounding_boxes_rtree();
923
924 std::vector<std::pair<
927 intersection;
928
929 for (const auto &cell1 :
931 {
932 intersection.resize(0);
934 cache1.get_mapping().get_bounding_box(cell1);
935 box1.extend(epsilon);
936 boost::geometry::index::query(tree0,
937 boost::geometry::index::intersects(
938 box1),
939 std::back_inserter(intersection));
940 if (!intersection.empty())
941 {
942 cell1->get_dof_indices(dofs1);
943 fev1.reinit(cell1);
944 for (const auto &entry : intersection)
945 {
947 *entry.second, &dh0);
948 cell0->get_dof_indices(dofs0);
949 fev0.reinit(cell0);
950 assemble_one_pair();
951 }
952 }
953 }
954 }
955 }
956#ifndef DOXYGEN
957# include "non_matching/coupling.inst"
958#endif
959} // namespace NonMatching
960
*  iterator end()
*  *  iterator begin()
void distribute_local_to_global(const InVector &local_vector, const std::vector< size_type > &local_dof_indices, OutVector &global_vector) const
void add_entries_local_to_global(const std::vector< size_type > &local_dof_indices, SparsityPatternBase &sparsity_pattern, const bool keep_constrained_entries=true, const Table< 2, bool > &dof_mask=Table< 2, bool >()) const
void extend(const Number amount)
unsigned int size() const
cell_iterator end() const
const FiniteElement< dim, spacedim > & get_fe(const types::fe_index index=0) const
const Triangulation< dim, spacedim > & get_triangulation() const
active_cell_iterator begin_active(const unsigned int level=0) const
types::global_dof_index n_dofs() const
unsigned int n_dofs_per_cell() const
unsigned int n_components() const
std::pair< unsigned int, unsigned int > system_to_component_index(const unsigned int index) const
virtual void value_list(const std::vector< Point< dim > > &points, std::vector< RangeNumberType > &values, const unsigned int component=0) const
virtual void set_radius(const double r)
virtual void set_center(const Point< dim > &p)
const Mapping< dim, spacedim > & get_mapping() const
const RTree< std::pair< BoundingBox< spacedim >, typename Triangulation< dim, spacedim >::active_cell_iterator > > & get_cell_bounding_boxes_rtree() const
Abstract base class for mapping classes.
Definition mapping.h:318
virtual BoundingBox< spacedim > get_bounding_box(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
void reinit(const TriaIterator< DoFCellAccessor< dim, dim, level_dof_access > > &cell, const unsigned int q_index=numbers::invalid_unsigned_int, const unsigned int mapping_index=numbers::invalid_unsigned_int)
Definition fe_values.cc:149
Definition point.h:111
unsigned int size() const
size_type n_rows() const
size_type n_cols() const
unsigned int n_active_cells() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
IteratorRange< active_cell_iterator > active_cell_iterators() const
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
typename ActiveSelector::cell_iterator cell_iterator
TriaActiveIterator< CellAccessor< dim, spacedim > > active_cell_iterator
Definition tria.h:1648
typename ActiveSelector::active_cell_iterator active_cell_iterator
@ update_values
Shape function values.
@ update_JxW_values
Transformed quadrature weights.
@ update_quadrature_points
Transformed quadrature points.
return_type compute_point_locations(const Cache< dim, spacedim > &cache, const std::vector< Point< spacedim > > &points, const typename Triangulation< dim, spacedim >::active_cell_iterator &cell_hint=typename Triangulation< dim, spacedim >::active_cell_iterator())
std::pair< std::vector< unsigned int >, std::vector< unsigned int > > compute_components_coupling(const ComponentMask &comps0, const ComponentMask &comps1, const FiniteElement< dim0, spacedim > &fe0, const FiniteElement< dim1, spacedim > &fe1)
Definition coupling.cc:137
std::pair< std::vector< Point< spacedim > >, std::vector< unsigned int > > qpoints_over_locally_owned_cells(const GridTools::Cache< dim0, spacedim > &cache, const DoFHandler< dim1, spacedim > &immersed_dh, const Quadrature< dim1 > &quad, const Mapping< dim1, spacedim > &immersed_mapping, const bool tria_is_parallel)
Definition coupling.cc:64
void create_coupling_sparsity_pattern(const DoFHandler< dim0, spacedim > &space_dh, const DoFHandler< dim1, spacedim > &immersed_dh, const Quadrature< dim1 > &quad, SparsityPatternBase &sparsity, const AffineConstraints< number > &constraints={}, const ComponentMask &space_comps={}, const ComponentMask &immersed_comps={}, const Mapping< dim0, spacedim > &space_mapping=StaticMappingQ1< dim0, spacedim >::mapping, const Mapping< dim1, spacedim > &immersed_mapping=StaticMappingQ1< dim1, spacedim >::mapping, const AffineConstraints< number > &immersed_constraints=AffineConstraints< number >())
Definition coupling.cc:171
void create_coupling_mass_matrix(const DoFHandler< dim0, spacedim > &space_dh, const DoFHandler< dim1, spacedim > &immersed_dh, const Quadrature< dim1 > &quad, Matrix &matrix, const AffineConstraints< typename Matrix::value_type > &constraints=AffineConstraints< typename Matrix::value_type >(), const ComponentMask &space_comps={}, const ComponentMask &immersed_comps={}, const Mapping< dim0, spacedim > &space_mapping=StaticMappingQ1< dim0, spacedim >::mapping, const Mapping< dim1, spacedim > &immersed_mapping=StaticMappingQ1< dim1, spacedim >::mapping, const AffineConstraints< typename Matrix::value_type > &immersed_constraints=AffineConstraints< typename Matrix::value_type >())
Definition coupling.cc:361
constexpr unsigned int invalid_unsigned_int
Definition types.h:236
*  const unsigned int n_q_points