deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\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
32
33#ifdef DEAL_II_WITH_TRILINOS
36
37# ifdef DEAL_II_TRILINOS_WITH_TPETRA
40# endif
41#endif
42
44
45#include <complex>
46#include <limits>
47
49namespace NonMatching
50{
51 namespace internal
52 {
70 template <int dim0, int dim1, int spacedim>
71 std::pair<std::vector<Point<spacedim>>, std::vector<unsigned int>>
74 const DoFHandler<dim1, spacedim> &immersed_dh,
75 const Quadrature<dim1> &quad,
76 const Mapping<dim1, spacedim> &immersed_mapping,
77 const bool tria_is_parallel)
78 {
79 const auto &immersed_fe = immersed_dh.get_fe();
80 std::vector<Point<spacedim>> points_over_local_cells;
81 // Keep track of which cells we actually used
82 std::vector<unsigned int> used_cells_ids;
83 {
84 FEValues<dim1, spacedim> fe_v(immersed_mapping,
85 immersed_fe,
86 quad,
88 unsigned int cell_id = 0;
89 for (const auto &cell : immersed_dh.active_cell_iterators())
90 {
91 bool use_cell = false;
92 if (tria_is_parallel)
93 {
94 const auto bbox = cell->bounding_box();
95 std::vector<std::pair<
98 out_vals;
100 boost::geometry::index::intersects(bbox),
101 std::back_inserter(out_vals));
102 // Each bounding box corresponds to an active cell
103 // of the embedding triangulation: we now check if
104 // the current cell, of the embedded triangulation,
105 // overlaps a locally owned cell of the embedding one
106 for (const auto &bbox_it : out_vals)
107 if (bbox_it.second->is_locally_owned())
108 {
109 use_cell = true;
110 used_cells_ids.emplace_back(cell_id);
111 break;
112 }
113 }
114 else
115 // for sequential triangulations, simply use all cells
116 use_cell = true;
117
118 if (use_cell)
119 {
120 // Reinitialize the cell and the fe_values
121 fe_v.reinit(cell);
122 const std::vector<Point<spacedim>> &x_points =
123 fe_v.get_quadrature_points();
124
125 // Insert the points to the vector
126 points_over_local_cells.insert(points_over_local_cells.end(),
127 x_points.begin(),
128 x_points.end());
129 }
130 ++cell_id;
131 }
132 }
133 return {std::move(points_over_local_cells), std::move(used_cells_ids)};
134 }
135
136
143 template <int dim0, int dim1, int spacedim>
144 std::pair<std::vector<unsigned int>, std::vector<unsigned int>>
146 const ComponentMask &comps1,
149 {
150 // Take care of components
151 const ComponentMask mask0 =
152 (comps0.size() == 0 ? ComponentMask(fe0.n_components(), true) : comps0);
153
154 const ComponentMask mask1 =
155 (comps1.size() == 0 ? ComponentMask(fe1.n_components(), true) : comps1);
156
157 AssertDimension(mask0.size(), fe0.n_components());
158 AssertDimension(mask1.size(), fe1.n_components());
159
160 // Global to local indices
161 std::vector<unsigned int> gtl0(fe0.n_components(),
163 std::vector<unsigned int> gtl1(fe1.n_components(),
165
166 for (unsigned int i = 0, j = 0; i < gtl0.size(); ++i)
167 if (mask0[i])
168 gtl0[i] = j++;
169
170 for (unsigned int i = 0, j = 0; i < gtl1.size(); ++i)
171 if (mask1[i])
172 gtl1[i] = j++;
173 return {gtl0, gtl1};
174 }
175 } // namespace internal
176
177 template <int dim0, int dim1, int spacedim, typename number>
178 void
180 const DoFHandler<dim0, spacedim> &space_dh,
181 const DoFHandler<dim1, spacedim> &immersed_dh,
182 const Quadrature<dim1> &quad,
183 SparsityPatternBase &sparsity,
184 const AffineConstraints<number> &constraints,
185 const ComponentMask &space_comps,
186 const ComponentMask &immersed_comps,
187 const Mapping<dim0, spacedim> &space_mapping,
188 const Mapping<dim1, spacedim> &immersed_mapping,
189 const AffineConstraints<number> &immersed_constraints)
190 {
192 space_mapping);
194 space_dh,
195 immersed_dh,
196 quad,
197 sparsity,
198 constraints,
199 space_comps,
200 immersed_comps,
201 immersed_mapping,
202 immersed_constraints);
203 }
204
205
206
207 template <int dim0, int dim1, int spacedim, typename number>
208 void
211 const DoFHandler<dim0, spacedim> &space_dh,
212 const DoFHandler<dim1, spacedim> &immersed_dh,
213 const Quadrature<dim1> &quad,
214 SparsityPatternBase &sparsity,
215 const AffineConstraints<number> &constraints,
216 const ComponentMask &space_comps,
217 const ComponentMask &immersed_comps,
218 const Mapping<dim1, spacedim> &immersed_mapping,
219 const AffineConstraints<number> &immersed_constraints)
220 {
221 AssertDimension(sparsity.n_rows(), space_dh.n_dofs());
222 AssertDimension(sparsity.n_cols(), immersed_dh.n_dofs());
223 Assert(dim1 <= dim0,
224 ExcMessage("This function can only work if dim1 <= dim0"));
225 Assert((dynamic_cast<
227 &immersed_dh.get_triangulation()) == nullptr),
229
230 const bool tria_is_parallel =
231 (dynamic_cast<const parallel::TriangulationBase<dim0, spacedim> *>(
232 &space_dh.get_triangulation()) != nullptr);
233 const auto &space_fe = space_dh.get_fe();
234 const auto &immersed_fe = immersed_dh.get_fe();
235
236 // Dof indices
237 std::vector<types::global_dof_index> dofs(immersed_fe.n_dofs_per_cell());
238 std::vector<types::global_dof_index> odofs(space_fe.n_dofs_per_cell());
239
240 // Take care of components
241 const ComponentMask space_c =
242 (space_comps.size() == 0 ? ComponentMask(space_fe.n_components(), true) :
243 space_comps);
244
245 const ComponentMask immersed_c =
246 (immersed_comps.size() == 0 ?
247 ComponentMask(immersed_fe.n_components(), true) :
248 immersed_comps);
249
250 AssertDimension(space_c.size(), space_fe.n_components());
251 AssertDimension(immersed_c.size(), immersed_fe.n_components());
252
253 // Global to local indices
254 std::vector<unsigned int> space_gtl(space_fe.n_components(),
256 std::vector<unsigned int> immersed_gtl(immersed_fe.n_components(),
258
259 for (unsigned int i = 0, j = 0; i < space_gtl.size(); ++i)
260 if (space_c[i])
261 space_gtl[i] = j++;
262
263 for (unsigned int i = 0, j = 0; i < immersed_gtl.size(); ++i)
264 if (immersed_c[i])
265 immersed_gtl[i] = j++;
266
267 const unsigned int n_q_points = quad.size();
268 const unsigned int n_active_c =
269 immersed_dh.get_triangulation().n_active_cells();
270
271 const auto qpoints_cells_data = internal::qpoints_over_locally_owned_cells(
272 cache, immersed_dh, quad, immersed_mapping, tria_is_parallel);
273
274 const auto &points_over_local_cells = std::get<0>(qpoints_cells_data);
275 const auto &used_cells_ids = std::get<1>(qpoints_cells_data);
276
277 // [TODO]: when the add_entries_local_to_global below will implement
278 // the version with the dof_mask, this should be uncommented.
279 //
280 // // Construct a dof_mask, used to distribute entries to the sparsity
281 // able< 2, bool > dof_mask(space_fe.n_dofs_per_cell(),
282 // immersed_fe.n_dofs_per_cell());
283 // of_mask.fill(false);
284 // or (unsigned int i=0; i<space_fe.n_dofs_per_cell(); ++i)
285 // {
286 // const auto comp_i = space_fe.system_to_component_index(i).first;
287 // if (space_gtl[comp_i] != numbers::invalid_unsigned_int)
288 // for (unsigned int j=0; j<immersed_fe.n_dofs_per_cell(); ++j)
289 // {
290 // const auto comp_j =
291 // immersed_fe.system_to_component_index(j).first; if
292 // (immersed_gtl[comp_j] == space_gtl[comp_i])
293 // dof_mask(i,j) = true;
294 // }
295 // }
296
297
298 // Get a list of outer cells, qpoints and maps.
299 const auto cpm =
300 GridTools::compute_point_locations(cache, points_over_local_cells);
301 const auto &all_cells = std::get<0>(cpm);
302 const auto &maps = std::get<2>(cpm);
303
304 std::vector<
305 std::set<typename Triangulation<dim0, spacedim>::active_cell_iterator>>
306 cell_sets(n_active_c);
307
308 for (unsigned int i = 0; i < maps.size(); ++i)
309 {
310 // Quadrature points should be reasonably clustered:
311 // the following index keeps track of the last id
312 // where the current cell was inserted
313 unsigned int last_id = std::numeric_limits<unsigned int>::max();
314 unsigned int cell_id;
315 for (const unsigned int idx : maps[i])
316 {
317 // Find in which cell of immersed triangulation the point lies
318 if (tria_is_parallel)
319 cell_id = used_cells_ids[idx / n_q_points];
320 else
321 cell_id = idx / n_q_points;
322
323 if (last_id != cell_id)
324 {
325 cell_sets[cell_id].insert(all_cells[i]);
326 last_id = cell_id;
327 }
328 }
329 }
330
331 // Now we run on each cell of the immersed
332 // and build the sparsity
333 unsigned int i = 0;
334 for (const auto &cell : immersed_dh.active_cell_iterators())
335 {
336 // Reinitialize the cell
337 cell->get_dof_indices(dofs);
338
339 // List of outer cells
340 const auto &cells = cell_sets[i];
341
342 for (const auto &cell_c : cells)
343 {
344 // Get the ones in the current outer cell
345 typename DoFHandler<dim0, spacedim>::cell_iterator ocell(*cell_c,
346 &space_dh);
347 // Make sure we act only on locally_owned cells
348 if (ocell->is_locally_owned())
349 {
350 ocell->get_dof_indices(odofs);
351 // [TODO]: When the following function will be implemented
352 // for the case of non-trivial dof_mask, we should
353 // uncomment the missing part.
354 constraints.add_entries_local_to_global(
355 odofs,
356 immersed_constraints,
357 dofs,
358 sparsity); //, true, dof_mask);
359 }
360 }
361 ++i;
362 }
363 }
364
365
366
367 template <int dim0, int dim1, int spacedim, typename Matrix>
368 void
370 const DoFHandler<dim0, spacedim> &space_dh,
371 const DoFHandler<dim1, spacedim> &immersed_dh,
372 const Quadrature<dim1> &quad,
373 Matrix &matrix,
375 const ComponentMask &space_comps,
376 const ComponentMask &immersed_comps,
377 const Mapping<dim0, spacedim> &space_mapping,
378 const Mapping<dim1, spacedim> &immersed_mapping,
379 const AffineConstraints<typename Matrix::value_type> &immersed_constraints)
380 {
382 space_mapping);
384 space_dh,
385 immersed_dh,
386 quad,
387 matrix,
388 constraints,
389 space_comps,
390 immersed_comps,
391 immersed_mapping,
392 immersed_constraints);
393 }
394
395
396
397 template <int dim0, int dim1, int spacedim, typename Matrix>
398 void
401 const DoFHandler<dim0, spacedim> &space_dh,
402 const DoFHandler<dim1, spacedim> &immersed_dh,
403 const Quadrature<dim1> &quad,
404 Matrix &matrix,
406 const ComponentMask &space_comps,
407 const ComponentMask &immersed_comps,
408 const Mapping<dim1, spacedim> &immersed_mapping,
409 const AffineConstraints<typename Matrix::value_type> &immersed_constraints)
410 {
411 AssertDimension(matrix.m(), space_dh.n_dofs());
412 AssertDimension(matrix.n(), immersed_dh.n_dofs());
413 Assert(dim1 <= dim0,
414 ExcMessage("This function can only work if dim1 <= dim0"));
415 Assert((dynamic_cast<
417 &immersed_dh.get_triangulation()) == nullptr),
419
420 const bool tria_is_parallel =
421 (dynamic_cast<const parallel::TriangulationBase<dim0, spacedim> *>(
422 &space_dh.get_triangulation()) != nullptr);
423
424 const auto &space_fe = space_dh.get_fe();
425 const auto &immersed_fe = immersed_dh.get_fe();
426
427 // Dof indices
428 std::vector<types::global_dof_index> dofs(immersed_fe.n_dofs_per_cell());
429 std::vector<types::global_dof_index> odofs(space_fe.n_dofs_per_cell());
430
431 // Take care of components
432 const ComponentMask space_c =
433 (space_comps.size() == 0 ? ComponentMask(space_fe.n_components(), true) :
434 space_comps);
435
436 const ComponentMask immersed_c =
437 (immersed_comps.size() == 0 ?
438 ComponentMask(immersed_fe.n_components(), true) :
439 immersed_comps);
440
441 AssertDimension(space_c.size(), space_fe.n_components());
442 AssertDimension(immersed_c.size(), immersed_fe.n_components());
443
444 std::vector<unsigned int> space_gtl(space_fe.n_components(),
446 std::vector<unsigned int> immersed_gtl(immersed_fe.n_components(),
448
449 for (unsigned int i = 0, j = 0; i < space_gtl.size(); ++i)
450 if (space_c[i])
451 space_gtl[i] = j++;
452
453 for (unsigned int i = 0, j = 0; i < immersed_gtl.size(); ++i)
454 if (immersed_c[i])
455 immersed_gtl[i] = j++;
456
458 space_dh.get_fe().n_dofs_per_cell(),
459 immersed_dh.get_fe().n_dofs_per_cell());
460
461 FEValues<dim1, spacedim> fe_v(immersed_mapping,
462 immersed_dh.get_fe(),
463 quad,
466
467 const unsigned int n_q_points = quad.size();
468 const unsigned int n_active_c =
469 immersed_dh.get_triangulation().n_active_cells();
470
471 const auto used_cells_data = internal::qpoints_over_locally_owned_cells(
472 cache, immersed_dh, quad, immersed_mapping, tria_is_parallel);
473
474 const auto &points_over_local_cells = std::get<0>(used_cells_data);
475 const auto &used_cells_ids = std::get<1>(used_cells_data);
476
477 // Get a list of outer cells, qpoints and maps.
478 const auto cpm =
479 GridTools::compute_point_locations(cache, points_over_local_cells);
480 const auto &all_cells = std::get<0>(cpm);
481 const auto &all_qpoints = std::get<1>(cpm);
482 const auto &all_maps = std::get<2>(cpm);
483
484 std::vector<
485 std::vector<typename Triangulation<dim0, spacedim>::active_cell_iterator>>
486 cell_container(n_active_c);
487 std::vector<std::vector<std::vector<Point<dim0>>>> qpoints_container(
488 n_active_c);
489 std::vector<std::vector<std::vector<unsigned int>>> maps_container(
490 n_active_c);
491
492 // Cycle over all cells of underling mesh found
493 // call it omesh, elaborating the output
494 for (unsigned int o = 0; o < all_cells.size(); ++o)
495 {
496 for (unsigned int j = 0; j < all_maps[o].size(); ++j)
497 {
498 // Find the index of the "owner" cell and qpoint
499 // with regard to the immersed mesh
500 // Find in which cell of immersed triangulation the point lies
501 unsigned int cell_id;
502 if (tria_is_parallel)
503 cell_id = used_cells_ids[all_maps[o][j] / n_q_points];
504 else
505 cell_id = all_maps[o][j] / n_q_points;
506
507 const unsigned int n_pt = all_maps[o][j] % n_q_points;
508
509 // If there are no cells, we just add our data
510 if (cell_container[cell_id].empty())
511 {
512 cell_container[cell_id].emplace_back(all_cells[o]);
513 qpoints_container[cell_id].emplace_back(
514 std::vector<Point<dim0>>{all_qpoints[o][j]});
515 maps_container[cell_id].emplace_back(
516 std::vector<unsigned int>{n_pt});
517 }
518 // If there are already cells, we begin by looking
519 // at the last inserted cell, which is more likely:
520 else if (cell_container[cell_id].back() == all_cells[o])
521 {
522 qpoints_container[cell_id].back().emplace_back(
523 all_qpoints[o][j]);
524 maps_container[cell_id].back().emplace_back(n_pt);
525 }
526 else
527 {
528 // We don't need to check the last element
529 const auto cell_p = std::find(cell_container[cell_id].begin(),
530 cell_container[cell_id].end() - 1,
531 all_cells[o]);
532
533 if (cell_p == cell_container[cell_id].end() - 1)
534 {
535 cell_container[cell_id].emplace_back(all_cells[o]);
536 qpoints_container[cell_id].emplace_back(
537 std::vector<Point<dim0>>{all_qpoints[o][j]});
538 maps_container[cell_id].emplace_back(
539 std::vector<unsigned int>{n_pt});
540 }
541 else
542 {
543 const unsigned int pos =
544 cell_p - cell_container[cell_id].begin();
545 qpoints_container[cell_id][pos].emplace_back(
546 all_qpoints[o][j]);
547 maps_container[cell_id][pos].emplace_back(n_pt);
548 }
549 }
550 }
551 }
552
554 cell = immersed_dh.begin_active(),
555 endc = immersed_dh.end();
556
557 for (unsigned int j = 0; cell != endc; ++cell, ++j)
558 {
559 // Reinitialize the cell and the fe_values
560 fe_v.reinit(cell);
561 cell->get_dof_indices(dofs);
562
563 // Get a list of outer cells, qpoints and maps.
564 const auto &cells = cell_container[j];
565 const auto &qpoints = qpoints_container[j];
566 const auto &maps = maps_container[j];
567
568 for (unsigned int c = 0; c < cells.size(); ++c)
569 {
570 // Get the ones in the current outer cell
572 *cells[c], &space_dh);
573 // Make sure we act only on locally_owned cells
574 if (ocell->is_locally_owned())
575 {
576 const std::vector<Point<dim0>> &qps = qpoints[c];
577 const std::vector<unsigned int> &ids = maps[c];
578
580 space_dh.get_fe(),
581 qps,
583 o_fe_v.reinit(ocell);
584 ocell->get_dof_indices(odofs);
585
586 // Reset the matrices.
587 cell_matrix = typename Matrix::value_type();
588
589 for (unsigned int i = 0;
590 i < space_dh.get_fe().n_dofs_per_cell();
591 ++i)
592 {
593 const auto comp_i =
594 space_dh.get_fe().system_to_component_index(i).first;
595 if (space_gtl[comp_i] != numbers::invalid_unsigned_int)
596 for (unsigned int j = 0;
597 j < immersed_dh.get_fe().n_dofs_per_cell();
598 ++j)
599 {
600 const auto comp_j = immersed_dh.get_fe()
602 .first;
603 if (space_gtl[comp_i] == immersed_gtl[comp_j])
604 for (unsigned int oq = 0;
605 oq < o_fe_v.n_quadrature_points;
606 ++oq)
607 {
608 // Get the corresponding q point
609 const unsigned int q = ids[oq];
610
611 cell_matrix(i, j) +=
612 (fe_v.shape_value(j, q) *
613 o_fe_v.shape_value(i, oq) * fe_v.JxW(q));
614 }
615 }
616 }
617
618 // Now assemble the matrices
619 constraints.distribute_local_to_global(
620 cell_matrix, odofs, immersed_constraints, dofs, matrix);
621 }
622 }
623 }
624 }
625
626 template <int dim0, int dim1, int spacedim, typename Number>
627 void
629 const double &epsilon,
634 const Quadrature<dim1> &quad,
635 SparsityPatternBase &sparsity,
636 const AffineConstraints<Number> &constraints0,
637 const ComponentMask &comps0,
638 const ComponentMask &comps1)
639 {
640 if (epsilon == 0.0)
641 {
642 Assert(dim1 <= dim0,
643 ExcMessage("When epsilon is zero, you can only "
644 "call this function with dim1 <= dim0."));
646 dh0,
647 dh1,
648 quad,
649 sparsity,
650 constraints0,
651 comps0,
652 comps1,
653 cache1.get_mapping());
654 return;
655 }
656 AssertDimension(sparsity.n_rows(), dh0.n_dofs());
657 AssertDimension(sparsity.n_cols(), dh1.n_dofs());
658
659 const bool zero_is_distributed =
661 *>(&dh0.get_triangulation()) != nullptr);
662 const bool one_is_distributed =
664 *>(&dh1.get_triangulation()) != nullptr);
665
666 // We bail out if both are distributed triangulations
667 Assert(!zero_is_distributed || !one_is_distributed, ExcNotImplemented());
668
669 // If we can loop on both, we decide where to make the outer loop according
670 // to the size of the triangulation. The reasoning is the following:
671 // - cost for accessing the tree: log(N)
672 // - cost for computing the intersection for each of the outer loop cells: M
673 // Total cost (besides the setup) is: M log(N)
674 // If we can, make sure M is the smaller number of the two.
675 const bool outer_loop_on_zero =
676 (zero_is_distributed && !one_is_distributed) ||
679
680 const auto &fe0 = dh0.get_fe();
681 const auto &fe1 = dh1.get_fe();
682
683 // Dof indices
684 std::vector<types::global_dof_index> dofs0(fe0.n_dofs_per_cell());
685 std::vector<types::global_dof_index> dofs1(fe1.n_dofs_per_cell());
686
687 if (outer_loop_on_zero)
688 {
689 Assert(one_is_distributed == false, ExcInternalError());
690
691 const auto &tree1 = cache1.get_cell_bounding_boxes_rtree();
692
693 std::vector<std::pair<
696 intersection;
697
698 for (const auto &cell0 :
700 {
701 intersection.resize(0);
703 cache0.get_mapping().get_bounding_box(cell0);
704 box0.extend(epsilon);
705 boost::geometry::index::query(tree1,
706 boost::geometry::index::intersects(
707 box0),
708 std::back_inserter(intersection));
709 if (!intersection.empty())
710 {
711 cell0->get_dof_indices(dofs0);
712 for (const auto &entry : intersection)
713 {
715 *entry.second, &dh1);
716 cell1->get_dof_indices(dofs1);
717 constraints0.add_entries_local_to_global(dofs0,
718 dofs1,
719 sparsity);
720 }
721 }
722 }
723 }
724 else
725 {
726 Assert(zero_is_distributed == false, ExcInternalError());
727 const auto &tree0 = cache0.get_cell_bounding_boxes_rtree();
728
729 std::vector<std::pair<
732 intersection;
733
734 for (const auto &cell1 :
736 {
737 intersection.resize(0);
739 cache1.get_mapping().get_bounding_box(cell1);
740 box1.extend(epsilon);
741 boost::geometry::index::query(tree0,
742 boost::geometry::index::intersects(
743 box1),
744 std::back_inserter(intersection));
745 if (!intersection.empty())
746 {
747 cell1->get_dof_indices(dofs1);
748 for (const auto &entry : intersection)
749 {
751 *entry.second, &dh0);
752 cell0->get_dof_indices(dofs0);
753 constraints0.add_entries_local_to_global(dofs0,
754 dofs1,
755 sparsity);
756 }
757 }
758 }
759 }
760 }
761
762
763
764 template <int dim0, int dim1, int spacedim, typename Matrix>
765 void
768 const double &epsilon,
773 const Quadrature<dim0> &quadrature0,
774 const Quadrature<dim1> &quadrature1,
775 Matrix &matrix,
777 const ComponentMask &comps0,
778 const ComponentMask &comps1)
779 {
780 if (epsilon == 0)
781 {
782 Assert(dim1 <= dim0,
783 ExcMessage("When epsilon is zero, you can only "
784 "call this function with dim1 <= dim0."));
786 dh0,
787 dh1,
788 quadrature1,
789 matrix,
790 constraints0,
791 comps0,
792 comps1,
793 cache1.get_mapping());
794 return;
795 }
796
797 AssertDimension(matrix.m(), dh0.n_dofs());
798 AssertDimension(matrix.n(), dh1.n_dofs());
799
800 const bool zero_is_distributed =
802 *>(&dh0.get_triangulation()) != nullptr);
803 const bool one_is_distributed =
805 *>(&dh1.get_triangulation()) != nullptr);
806
807 // We bail out if both are distributed triangulations
808 Assert(!zero_is_distributed || !one_is_distributed, ExcNotImplemented());
809
810 // If we can loop on both, we decide where to make the outer loop according
811 // to the size of the triangulation. The reasoning is the following:
812 // - cost for accessing the tree: log(N)
813 // - cost for computing the intersection for each of the outer loop cells: M
814 // Total cost (besides the setup) is: M log(N)
815 // If we can, make sure M is the smaller number of the two.
816 const bool outer_loop_on_zero =
817 (zero_is_distributed && !one_is_distributed) ||
820
821 const auto &fe0 = dh0.get_fe();
822 const auto &fe1 = dh1.get_fe();
823
825 fe0,
826 quadrature0,
829
831 fe1,
832 quadrature1,
835
836 // Dof indices
837 std::vector<types::global_dof_index> dofs0(fe0.n_dofs_per_cell());
838 std::vector<types::global_dof_index> dofs1(fe1.n_dofs_per_cell());
839
840 // Local Matrix
841 FullMatrix<typename Matrix::value_type> cell_matrix(fe0.n_dofs_per_cell(),
842 fe1.n_dofs_per_cell());
843
844 // Global to local indices
845 const auto p =
846 internal::compute_components_coupling(comps0, comps1, fe0, fe1);
847 const auto &gtl0 = p.first;
848 const auto &gtl1 = p.second;
849
850 kernel.set_radius(epsilon);
851 std::vector<double> kernel_values(quadrature1.size());
852
853 auto assemble_one_pair = [&]() {
854 cell_matrix = 0;
855 for (unsigned int q0 = 0; q0 < quadrature0.size(); ++q0)
856 {
857 kernel.set_center(fev0.quadrature_point(q0));
858 kernel.value_list(fev1.get_quadrature_points(), kernel_values);
859 for (unsigned int j = 0; j < fe1.n_dofs_per_cell(); ++j)
860 {
861 const auto comp_j = fe1.system_to_component_index(j).first;
862
863 // First compute the part of the integral that does not
864 // depend on i
865 typename Matrix::value_type sum_q1 = {};
866 for (unsigned int q1 = 0; q1 < quadrature1.size(); ++q1)
867 sum_q1 +=
868 fev1.shape_value(j, q1) * kernel_values[q1] * fev1.JxW(q1);
869 sum_q1 *= fev0.JxW(q0);
870
871 // Now compute the main integral with the sum over q1 already
872 // completed - this gives a cubic complexity as usual rather
873 // than a quartic one with naive loops
874 for (unsigned int i = 0; i < fe0.n_dofs_per_cell(); ++i)
875 {
876 const auto comp_i = fe0.system_to_component_index(i).first;
877 if (gtl0[comp_i] != numbers::invalid_unsigned_int &&
878 gtl1[comp_j] == gtl0[comp_i])
879 cell_matrix(i, j) += fev0.shape_value(i, q0) * sum_q1;
880 }
881 }
882 }
883
884 constraints0.distribute_local_to_global(cell_matrix,
885 dofs0,
886 dofs1,
887 matrix);
888 };
889
890 if (outer_loop_on_zero)
891 {
892 Assert(one_is_distributed == false, ExcInternalError());
893
894 const auto &tree1 = cache1.get_cell_bounding_boxes_rtree();
895
896 std::vector<std::pair<
899 intersection;
900
901 for (const auto &cell0 :
903 {
904 intersection.resize(0);
906 cache0.get_mapping().get_bounding_box(cell0);
907 box0.extend(epsilon);
908 boost::geometry::index::query(tree1,
909 boost::geometry::index::intersects(
910 box0),
911 std::back_inserter(intersection));
912 if (!intersection.empty())
913 {
914 cell0->get_dof_indices(dofs0);
915 fev0.reinit(cell0);
916 for (const auto &entry : intersection)
917 {
919 *entry.second, &dh1);
920 cell1->get_dof_indices(dofs1);
921 fev1.reinit(cell1);
922 assemble_one_pair();
923 }
924 }
925 }
926 }
927 else
928 {
929 Assert(zero_is_distributed == false, ExcInternalError());
930 const auto &tree0 = cache0.get_cell_bounding_boxes_rtree();
931
932 std::vector<std::pair<
935 intersection;
936
937 for (const auto &cell1 :
939 {
940 intersection.resize(0);
942 cache1.get_mapping().get_bounding_box(cell1);
943 box1.extend(epsilon);
944 boost::geometry::index::query(tree0,
945 boost::geometry::index::intersects(
946 box1),
947 std::back_inserter(intersection));
948 if (!intersection.empty())
949 {
950 cell1->get_dof_indices(dofs1);
951 fev1.reinit(cell1);
952 for (const auto &entry : intersection)
953 {
955 *entry.second, &dh0);
956 cell0->get_dof_indices(dofs0);
957 fev0.reinit(cell0);
958 assemble_one_pair();
959 }
960 }
961 }
962 }
963 }
964#ifndef DOXYGEN
965# include "non_matching/coupling.inst"
966#endif
967} // namespace NonMatching
968
*  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
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:145
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:72
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:179
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:369
constexpr unsigned int invalid_unsigned_int
Definition types.h:228