9 #include "DirichletBC.h"
13 #include <dolfinx/common/IndexMap.h>
14 #include <dolfinx/common/types.h>
15 #include <dolfinx/fem/Constant.h>
16 #include <dolfinx/fem/FunctionSpace.h>
17 #include <dolfinx/graph/AdjacencyList.h>
18 #include <dolfinx/mesh/Geometry.h>
19 #include <dolfinx/mesh/Mesh.h>
20 #include <dolfinx/mesh/Topology.h>
24 #include <xtensor/xbuilder.hpp>
25 #include <xtensor/xtensor.hpp>
27 namespace dolfinx::fem::impl
39 template <
typename T,
int _bs0 = -1,
int _bs1 = -1>
41 xtl::span<T> b,
const mesh::Geometry& geometry,
42 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
43 const std::uint8_t*)>& kernel,
44 const xtl::span<const std::int32_t>& active_cells,
45 const std::function<
void(
const xtl::span<T>&,
46 const xtl::span<const std::uint32_t>&,
47 std::int32_t,
int)>& dof_transform,
48 const graph::AdjacencyList<std::int32_t>& dofmap0,
int bs0,
49 const std::function<
void(
const xtl::span<T>&,
50 const xtl::span<const std::uint32_t>&,
51 std::int32_t,
int)>& dof_transform_to_transpose,
52 const graph::AdjacencyList<std::int32_t>& dofmap1,
int bs1,
53 const xtl::span<const T>& constants,
const array2d<T>& coeffs,
54 const xtl::span<const std::uint32_t>& cell_info,
55 const xtl::span<const T>& bc_values1,
const std::vector<bool>& bc_markers1,
56 const xtl::span<const T>& x0,
double scale)
58 assert(_bs0 < 0 or _bs0 == bs0);
59 assert(_bs1 < 0 or _bs1 == bs1);
62 const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
65 const std::size_t num_dofs_g = x_dofmap.num_links(0);
66 const xt::xtensor<double, 2>& x_g = geometry.x();
69 std::vector<double> coordinate_dofs(3 * num_dofs_g);
70 std::vector<T> Ae, be;
71 for (std::int32_t c : active_cells)
74 auto dmap1 = dofmap1.links(c);
78 for (std::size_t j = 0; j < dmap1.size(); ++j)
80 if constexpr (_bs1 > 0)
82 for (
int k = 0; k < _bs1; ++k)
84 assert(_bs1 * dmap1[j] + k < (
int)bc_markers1.size());
85 if (bc_markers1[_bs1 * dmap1[j] + k])
94 for (
int k = 0; k < bs1; ++k)
96 assert(bs1 * dmap1[j] + k < (
int)bc_markers1.size());
97 if (bc_markers1[bs1 * dmap1[j] + k])
110 auto x_dofs = x_dofmap.links(c);
111 for (std::size_t i = 0; i < x_dofs.size(); ++i)
113 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), 3,
114 std::next(coordinate_dofs.begin(), i * 3));
118 auto dmap0 = dofmap0.links(c);
120 const int num_rows = bs0 * dmap0.size();
121 const int num_cols = bs1 * dmap1.size();
123 auto coeff_array = coeffs.row(c);
124 Ae.resize(num_rows * num_cols);
125 std::fill(Ae.begin(), Ae.end(), 0);
126 kernel(Ae.data(), coeff_array.data(), constants.data(),
127 coordinate_dofs.data(),
nullptr,
nullptr);
128 dof_transform(Ae, cell_info, c, num_cols);
129 dof_transform_to_transpose(Ae, cell_info, c, num_rows);
133 std::fill(be.begin(), be.end(), 0);
134 for (std::size_t j = 0; j < dmap1.size(); ++j)
136 if constexpr (_bs1 > 0)
138 for (
int k = 0; k < _bs1; ++k)
140 const std::int32_t jj = _bs1 * dmap1[j] + k;
141 assert(jj < (
int)bc_markers1.size());
144 const T bc = bc_values1[jj];
145 const T _x0 = x0.empty() ? 0.0 : x0[jj];
148 for (
int m = 0; m < num_rows; ++m)
149 be[m] -= Ae[m * num_cols + _bs1 * j + k] * scale * (bc - _x0);
155 for (
int k = 0; k < bs1; ++k)
157 const std::int32_t jj = bs1 * dmap1[j] + k;
158 assert(jj < (
int)bc_markers1.size());
161 const T bc = bc_values1[jj];
162 const T _x0 = x0.empty() ? 0.0 : x0[jj];
164 for (
int m = 0; m < num_rows; ++m)
165 be[m] -= Ae[m * num_cols + bs1 * j + k] * scale * (bc - _x0);
171 for (std::size_t i = 0; i < dmap0.size(); ++i)
173 if constexpr (_bs0 > 0)
175 for (
int k = 0; k < _bs0; ++k)
176 b[_bs0 * dmap0[i] + k] += be[_bs0 * i + k];
180 for (
int k = 0; k < bs0; ++k)
181 b[bs0 * dmap0[i] + k] += be[bs0 * i + k];
193 template <
typename T,
int _bs = -1>
194 void _lift_bc_exterior_facets(
195 xtl::span<T> b,
const mesh::Mesh& mesh,
196 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
197 const std::uint8_t*)>& kernel,
198 const xtl::span<const std::int32_t>& active_facets,
199 const std::function<
void(
const xtl::span<T>&,
200 const xtl::span<const std::uint32_t>&,
201 std::int32_t,
int)>& dof_transform,
202 const graph::AdjacencyList<std::int32_t>& dofmap0,
int bs0,
203 const std::function<
void(
const xtl::span<T>&,
204 const xtl::span<const std::uint32_t>&,
205 std::int32_t,
int)>& dof_transform_to_transpose,
206 const graph::AdjacencyList<std::int32_t>& dofmap1,
int bs1,
207 const xtl::span<const T>& constants,
const array2d<T>& coeffs,
208 const xtl::span<const std::uint32_t>& cell_info,
209 const std::function<std::uint8_t(std::size_t)>& get_perm,
210 const xtl::span<const T>& bc_values1,
const std::vector<bool>& bc_markers1,
211 const xtl::span<const T>& x0,
double scale)
213 const int tdim = mesh.topology().dim();
216 const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
219 const std::size_t num_dofs_g = x_dofmap.num_links(0);
220 const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
223 std::vector<double> coordinate_dofs(3 * num_dofs_g);
224 std::vector<T> Ae, be;
227 const mesh::Topology& topology = mesh.topology();
228 auto connectivity = topology.connectivity(tdim - 1, tdim);
229 assert(connectivity);
230 auto c_to_f = topology.connectivity(tdim, tdim - 1);
232 auto map = topology.index_map(tdim - 1);
235 for (std::int32_t f : active_facets)
238 assert(connectivity->num_links(f) == 1);
239 const std::int32_t cell = connectivity->links(f)[0];
242 auto facets = c_to_f->links(cell);
243 auto it = std::find(facets.begin(), facets.end(), f);
244 assert(it != facets.end());
245 const int local_facet = std::distance(facets.begin(), it);
248 auto dmap1 = dofmap1.links(cell);
252 for (std::size_t j = 0; j < dmap1.size(); ++j)
254 for (
int k = 0; k < bs1; ++k)
256 if (bc_markers1[bs1 * dmap1[j] + k])
268 auto x_dofs = x_dofmap.links(cell);
269 for (std::size_t i = 0; i < x_dofs.size(); ++i)
271 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), 3,
272 std::next(coordinate_dofs.begin(), 3 * i));
276 auto dmap0 = dofmap0.links(cell);
278 const int num_rows = bs0 * dmap0.size();
279 const int num_cols = bs1 * dmap1.size();
281 auto coeff_array = coeffs.row(cell);
282 Ae.resize(num_rows * num_cols);
283 std::fill(Ae.begin(), Ae.end(), 0);
284 const std::uint8_t perm = get_perm(cell * facets.size() + local_facet);
285 kernel(Ae.data(), coeff_array.data(), constants.data(),
286 coordinate_dofs.data(), &local_facet, &perm);
287 dof_transform(Ae, cell_info, cell, num_cols);
288 dof_transform_to_transpose(Ae, cell_info, cell, num_rows);
292 std::fill(be.begin(), be.end(), 0);
293 for (std::size_t j = 0; j < dmap1.size(); ++j)
295 for (
int k = 0; k < bs1; ++k)
297 const std::int32_t jj = bs1 * dmap1[j] + k;
300 const T bc = bc_values1[jj];
301 const T _x0 = x0.empty() ? 0.0 : x0[jj];
303 for (
int m = 0; m < num_rows; ++m)
304 be[m] -= Ae[m * num_cols + bs1 * j + k] * scale * (bc - _x0);
309 for (std::size_t i = 0; i < dmap0.size(); ++i)
310 for (
int k = 0; k < bs0; ++k)
311 b[bs0 * dmap0[i] + k] += be[bs0 * i + k];
321 template <
typename T,
int _bs = -1>
322 void _lift_bc_interior_facets(
323 xtl::span<T> b,
const mesh::Mesh& mesh,
324 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
325 const std::uint8_t*)>& kernel,
326 const xtl::span<const std::int32_t>& active_facets,
327 const std::function<
void(
const xtl::span<T>&,
328 const xtl::span<const std::uint32_t>&,
329 std::int32_t,
int)>& dof_transform,
330 const graph::AdjacencyList<std::int32_t>& dofmap0,
int bs0,
331 const std::function<
void(
const xtl::span<T>&,
332 const xtl::span<const std::uint32_t>&,
333 std::int32_t,
int)>& dof_transform_to_transpose,
334 const graph::AdjacencyList<std::int32_t>& dofmap1,
int bs1,
335 const xtl::span<const T>& constants,
const array2d<T>& coeffs,
336 const std::vector<int>& offsets,
337 const xtl::span<const std::uint32_t>& cell_info,
338 const std::function<std::uint8_t(std::size_t)>& get_perm,
339 const xtl::span<const T>& bc_values1,
const std::vector<bool>& bc_markers1,
340 const xtl::span<const T>& x0,
double scale)
342 const int tdim = mesh.topology().dim();
345 const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
348 const std::size_t num_dofs_g = x_dofmap.num_links(0);
349 const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
352 xt::xtensor<double, 3> coordinate_dofs({2, num_dofs_g, 3});
353 std::vector<T> coeff_array(2 * offsets.back());
354 assert(offsets.back() ==
int(coeffs.shape[1]));
355 std::vector<T> Ae, be;
358 std::vector<std::int32_t> dmapjoint0, dmapjoint1;
360 const mesh::Topology& topology = mesh.topology();
361 auto connectivity = topology.connectivity(tdim - 1, tdim);
362 assert(connectivity);
363 auto c_to_f = topology.connectivity(tdim, tdim - 1);
365 auto f_to_c = topology.connectivity(tdim - 1, tdim);
367 auto map = topology.index_map(tdim - 1);
370 for (std::int32_t f : active_facets)
373 auto cells = f_to_c->links(f);
374 assert(
cells.size() == 2);
377 auto facets0 = c_to_f->links(cells[0]);
378 auto it0 = std::find(facets0.begin(), facets0.end(), f);
379 assert(it0 != facets0.end());
380 const int local_facet0 = std::distance(facets0.begin(), it0);
381 auto facets1 = c_to_f->links(cells[1]);
382 auto it1 = std::find(facets1.begin(), facets1.end(), f);
383 assert(it1 != facets1.end());
384 const int local_facet1 = std::distance(facets1.begin(), it1);
386 const std::array local_facet{local_facet0, local_facet1};
389 auto x_dofs0 = x_dofmap.links(cells[0]);
390 for (std::size_t i = 0; i < x_dofs0.size(); ++i)
392 std::copy_n(xt::view(x_g, x_dofs0[i]).begin(), 3,
393 xt::view(coordinate_dofs, 0, i, xt::all()).begin());
395 auto x_dofs1 = x_dofmap.links(cells[1]);
396 for (std::size_t i = 0; i < x_dofs1.size(); ++i)
398 std::copy_n(xt::view(x_g, x_dofs1[i]).begin(), 3,
399 xt::view(coordinate_dofs, 1, i, xt::all()).begin());
403 const xtl::span<const std::int32_t> dmap0_cell0 = dofmap0.links(cells[0]);
404 const xtl::span<const std::int32_t> dmap0_cell1 = dofmap0.links(cells[1]);
405 dmapjoint0.resize(dmap0_cell0.size() + dmap0_cell1.size());
406 std::copy(dmap0_cell0.begin(), dmap0_cell0.end(), dmapjoint0.begin());
407 std::copy(dmap0_cell1.begin(), dmap0_cell1.end(),
408 std::next(dmapjoint0.begin(), dmap0_cell0.size()));
410 const xtl::span<const std::int32_t> dmap1_cell0 = dofmap1.links(cells[0]);
411 const xtl::span<const std::int32_t> dmap1_cell1 = dofmap1.links(cells[1]);
412 dmapjoint1.resize(dmap1_cell0.size() + dmap1_cell1.size());
413 std::copy(dmap1_cell0.begin(), dmap1_cell0.end(), dmapjoint1.begin());
414 std::copy(dmap1_cell1.begin(), dmap1_cell1.end(),
415 std::next(dmapjoint1.begin(), dmap1_cell0.size()));
419 for (std::size_t j = 0; j < dmap1_cell0.size(); ++j)
421 for (
int k = 0; k < bs1; ++k)
423 if (bc_markers1[bs1 * dmap1_cell0[j] + k])
432 for (std::size_t j = 0; j < dmap1_cell1.size(); ++j)
434 for (
int k = 0; k < bs1; ++k)
436 if (bc_markers1[bs1 * dmap1_cell1[j] + k])
449 const auto coeff_cell0 = coeffs.row(cells[0]);
450 const auto coeff_cell1 = coeffs.row(cells[1]);
453 for (std::size_t i = 0; i < offsets.size() - 1; ++i)
456 const int num_entries = offsets[i + 1] - offsets[i];
457 std::copy_n(coeff_cell0.data() + offsets[i], num_entries,
458 std::next(coeff_array.begin(), 2 * offsets[i]));
459 std::copy_n(coeff_cell1.data() + offsets[i], num_entries,
460 std::next(coeff_array.begin(), offsets[i + 1] + offsets[i]));
463 const int num_rows = bs0 * dmapjoint0.size();
464 const int num_cols = bs1 * dmapjoint1.size();
467 Ae.resize(num_rows * num_cols);
468 std::fill(Ae.begin(), Ae.end(), 0);
469 const int facets_per_cell = facets0.size();
470 const std::array perm{
471 get_perm(cells[0] * facets_per_cell + local_facet[0]),
472 get_perm(cells[1] * facets_per_cell + local_facet[1])};
473 kernel(Ae.data(), coeff_array.data(), constants.data(),
474 coordinate_dofs.data(), local_facet.data(), perm.data());
475 dof_transform(Ae, cell_info, cells[0], num_cols);
476 dof_transform_to_transpose(Ae, cell_info, cells[0], num_rows);
479 std::fill(be.begin(), be.end(), 0);
482 for (std::size_t j = 0; j < dmap1_cell0.size(); ++j)
484 for (
int k = 0; k < bs1; ++k)
486 const std::int32_t jj = bs1 * dmap1_cell0[j] + k;
489 const T bc = bc_values1[jj];
490 const T _x0 = x0.empty() ? 0.0 : x0[jj];
492 for (
int m = 0; m < num_rows; ++m)
493 be[m] -= Ae[m * num_cols + bs1 * j + k] * scale * (bc - _x0);
499 const int offset = bs1 * dmap1_cell0.size();
500 for (std::size_t j = 0; j < dmap1_cell1.size(); ++j)
502 for (
int k = 0; k < bs1; ++k)
504 const std::int32_t jj = bs1 * dmap1_cell1[j] + k;
507 const T bc = bc_values1[jj];
508 const T _x0 = x0.empty() ? 0.0 : x0[jj];
510 for (
int m = 0; m < num_rows; ++m)
513 -= Ae[m * num_cols + offset + bs1 * j + k] * scale * (bc - _x0);
519 for (std::size_t i = 0; i < dmap0_cell0.size(); ++i)
520 for (
int k = 0; k < bs0; ++k)
521 b[bs0 * dmap0_cell0[i] + k] += be[bs0 * i + k];
523 for (std::size_t i = 0; i < dmap0_cell1.size(); ++i)
524 for (
int k = 0; k < bs0; ++k)
525 b[bs0 * dmap0_cell1[i] + k] += be[offset + bs0 * i + k];
534 template <
typename T,
int _bs = -1>
536 const std::function<
void(
const xtl::span<T>&,
537 const xtl::span<const std::uint32_t>&,
538 std::int32_t,
int)>& dof_transform,
539 xtl::span<T> b,
const mesh::Geometry& geometry,
540 const xtl::span<const std::int32_t>& active_cells,
541 const graph::AdjacencyList<std::int32_t>& dofmap,
int bs,
542 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
543 const std::uint8_t*)>& kernel,
544 const xtl::span<const T>& constants,
const array2d<T>& coeffs,
545 const xtl::span<const std::uint32_t>& cell_info)
547 assert(_bs < 0 or _bs == bs);
550 const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
553 const int num_dofs_g = x_dofmap.num_links(0);
554 const xt::xtensor<double, 2>& x_g = geometry.x();
558 const int num_dofs = dofmap.links(0).size();
559 std::vector<double> coordinate_dofs(3 * num_dofs_g);
560 std::vector<T> be(bs * num_dofs);
561 const xtl::span<T> _be(be);
564 for (std::int32_t c : active_cells)
567 auto x_dofs = x_dofmap.links(c);
568 for (std::size_t i = 0; i < x_dofs.size(); ++i)
570 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), 3,
571 std::next(coordinate_dofs.begin(), 3 * i));
575 std::fill(be.begin(), be.end(), 0);
576 kernel(be.data(), coeffs.row(c).data(), constants.data(),
577 coordinate_dofs.data(),
nullptr,
nullptr);
578 dof_transform(_be, cell_info, c, 1);
581 auto dofs = dofmap.links(c);
582 if constexpr (_bs > 0)
584 for (
int i = 0; i < num_dofs; ++i)
585 for (
int k = 0; k < _bs; ++k)
586 b[_bs * dofs[i] + k] += be[_bs * i + k];
590 for (
int i = 0; i < num_dofs; ++i)
591 for (
int k = 0; k < bs; ++k)
592 b[bs * dofs[i] + k] += be[bs * i + k];
603 template <
typename T,
int _bs = -1>
604 void assemble_exterior_facets(
605 const std::function<
void(
const xtl::span<T>&,
606 const xtl::span<const std::uint32_t>&,
607 std::int32_t,
int)>& dof_transform,
608 xtl::span<T> b,
const mesh::Mesh& mesh,
609 const xtl::span<const std::int32_t>& active_facets,
610 const graph::AdjacencyList<std::int32_t>& dofmap,
const int bs,
611 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
612 const std::uint8_t*)>& fn,
613 const xtl::span<const T>& constants,
const array2d<T>& coeffs,
614 const xtl::span<const std::uint32_t>& cell_info,
615 const std::function<std::uint8_t(std::size_t)>& get_perm)
617 assert(_bs < 0 or _bs == bs);
619 const int tdim = mesh.topology().dim();
622 const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
625 const std::size_t num_dofs_g = x_dofmap.num_links(0);
626 const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
630 const int num_dofs = dofmap.links(0).size();
631 std::vector<double> coordinate_dofs(3 * num_dofs_g);
632 std::vector<T> be(bs * num_dofs);
633 const xtl::span<T> _be(be);
635 auto f_to_c = mesh.topology().connectivity(tdim - 1, tdim);
637 auto c_to_f = mesh.topology().connectivity(tdim, tdim - 1);
639 for (std::int32_t f : active_facets)
642 assert(f_to_c->num_links(f) > 0);
643 const std::int32_t cell = f_to_c->links(f)[0];
646 auto facets = c_to_f->links(cell);
647 auto it = std::find(facets.begin(), facets.end(), f);
648 assert(it != facets.end());
649 const int local_facet = std::distance(facets.begin(), it);
652 auto x_dofs = x_dofmap.links(cell);
653 for (std::size_t i = 0; i < x_dofs.size(); ++i)
655 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), 3,
656 std::next(coordinate_dofs.begin(), 3 * i));
660 std::fill(be.begin(), be.end(), 0);
661 const std::uint8_t perm = get_perm(cell * facets.size() + local_facet);
662 fn(be.data(), coeffs.row(cell).data(), constants.data(),
663 coordinate_dofs.data(), &local_facet, &perm);
665 dof_transform(_be, cell_info, cell, 1);
668 auto dofs = dofmap.links(cell);
669 if constexpr (_bs > 0)
671 for (
int i = 0; i < num_dofs; ++i)
672 for (
int k = 0; k < _bs; ++k)
673 b[_bs * dofs[i] + k] += be[_bs * i + k];
677 for (
int i = 0; i < num_dofs; ++i)
678 for (
int k = 0; k < bs; ++k)
679 b[bs * dofs[i] + k] += be[bs * i + k];
690 template <
typename T,
int _bs = -1>
691 void assemble_interior_facets(
692 const std::function<
void(
const xtl::span<T>&,
693 const xtl::span<const std::uint32_t>&,
694 std::int32_t,
int)>& dof_transform,
695 xtl::span<T> b,
const mesh::Mesh& mesh,
696 const xtl::span<const std::int32_t>& active_facets,
697 const fem::DofMap& dofmap,
698 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
699 const std::uint8_t*)>& fn,
700 const xtl::span<const T>& constants,
const array2d<T>& coeffs,
701 const xtl::span<const int>& offsets,
702 const xtl::span<const std::uint32_t>& cell_info,
703 const std::function<std::uint8_t(std::size_t)>& get_perm)
705 const int tdim = mesh.topology().dim();
708 const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
711 const std::size_t num_dofs_g = x_dofmap.num_links(0);
712 const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
715 xt::xtensor<double, 3> coordinate_dofs({2, num_dofs_g, 3});
717 std::vector<T> coeff_array(2 * offsets.back());
718 assert(offsets.back() ==
int(coeffs.shape[1]));
720 const int bs = dofmap.bs();
721 assert(_bs < 0 or _bs == bs);
722 auto f_to_c = mesh.topology().connectivity(tdim - 1, tdim);
724 auto c_to_f = mesh.topology().connectivity(tdim, tdim - 1);
726 for (std::int32_t f : active_facets)
729 auto cells = f_to_c->links(f);
730 assert(
cells.size() == 2);
732 const int facets_per_cell = c_to_f->num_links(cells[0]);
735 std::array<int, 2> local_facet;
736 for (
int i = 0; i < 2; ++i)
738 auto facets = c_to_f->links(cells[i]);
739 auto it = std::find(facets.begin(), facets.end(), f);
740 assert(it != facets.end());
741 local_facet[i] = std::distance(facets.begin(), it);
745 auto x_dofs0 = x_dofmap.links(cells[0]);
746 for (std::size_t i = 0; i < x_dofs0.size(); ++i)
748 std::copy_n(xt::view(x_g, x_dofs0[i]).begin(), 3,
749 xt::view(coordinate_dofs, 0, i, xt::all()).begin());
751 auto x_dofs1 = x_dofmap.links(cells[1]);
752 for (std::size_t i = 0; i < x_dofs1.size(); ++i)
754 std::copy_n(xt::view(x_g, x_dofs1[i]).begin(), 3,
755 xt::view(coordinate_dofs, 1, i, xt::all()).begin());
760 auto coeff_cell0 = coeffs.row(cells[0]);
761 auto coeff_cell1 = coeffs.row(cells[1]);
764 for (std::size_t i = 0; i < offsets.size() - 1; ++i)
767 const int num_entries = offsets[i + 1] - offsets[i];
768 std::copy_n(coeff_cell0.data() + offsets[i], num_entries,
769 std::next(coeff_array.begin(), 2 * offsets[i]));
770 std::copy_n(coeff_cell1.data() + offsets[i], num_entries,
771 std::next(coeff_array.begin(), offsets[i + 1] + offsets[i]));
775 xtl::span<const std::int32_t> dmap0 = dofmap.cell_dofs(cells[0]);
776 xtl::span<const std::int32_t> dmap1 = dofmap.cell_dofs(cells[1]);
779 be.resize(bs * (dmap0.size() + dmap1.size()));
780 std::fill(be.begin(), be.end(), 0);
781 const std::array perm{
782 get_perm(cells[0] * facets_per_cell + local_facet[0]),
783 get_perm(cells[1] * facets_per_cell + local_facet[1])};
784 fn(be.data(), coeff_array.data(), constants.data(), coordinate_dofs.data(),
785 local_facet.data(), perm.data());
787 dof_transform(be, cell_info, cells[0], 1);
790 if constexpr (_bs > 0)
792 for (std::size_t i = 0; i < dmap0.size(); ++i)
793 for (
int k = 0; k < _bs; ++k)
794 b[_bs * dmap0[i] + k] += be[_bs * i + k];
795 for (std::size_t i = 0; i < dmap1.size(); ++i)
796 for (
int k = 0; k < _bs; ++k)
797 b[_bs * dmap1[i] + k] += be[_bs * (i + dmap0.size()) + k];
801 for (std::size_t i = 0; i < dmap0.size(); ++i)
802 for (
int k = 0; k < bs; ++k)
803 b[bs * dmap0[i] + k] += be[bs * i + k];
804 for (std::size_t i = 0; i < dmap1.size(); ++i)
805 for (
int k = 0; k < bs; ++k)
806 b[bs * dmap1[i] + k] += be[bs * (i + dmap0.size()) + k];
825 template <
typename T>
826 void lift_bc(xtl::span<T> b,
const Form<T>& a,
827 const xtl::span<const T>& constants,
const array2d<T>& coeffs,
828 const xtl::span<const T>& bc_values1,
829 const std::vector<bool>& bc_markers1,
const xtl::span<const T>& x0,
832 std::shared_ptr<const mesh::Mesh> mesh = a.mesh();
834 const int tdim = mesh->topology().dim();
837 assert(a.function_spaces().at(0));
838 assert(a.function_spaces().at(1));
839 const graph::AdjacencyList<std::int32_t>& dofmap0
840 = a.function_spaces()[0]->dofmap()->list();
841 const int bs0 = a.function_spaces()[0]->dofmap()->bs();
842 std::shared_ptr<const fem::FiniteElement> element0
843 = a.function_spaces()[0]->element();
844 const graph::AdjacencyList<std::int32_t>& dofmap1
845 = a.function_spaces()[1]->dofmap()->list();
846 const int bs1 = a.function_spaces()[1]->dofmap()->bs();
847 std::shared_ptr<const fem::FiniteElement> element1
848 = a.function_spaces()[1]->element();
850 const bool needs_transformation_data
851 = element0->needs_dof_transformations()
852 or element1->needs_dof_transformations()
853 or a.needs_facet_permutations();
855 xtl::span<const std::uint32_t> cell_info;
856 if (needs_transformation_data)
858 mesh->topology_mutable().create_entity_permutations();
859 cell_info = xtl::span(mesh->topology().get_cell_permutation_info());
862 const std::function<void(
const xtl::span<T>&,
863 const xtl::span<const std::uint32_t>&, std::int32_t,
865 dof_transform = element0->get_dof_transformation_function<T>();
866 const std::function<void(
const xtl::span<T>&,
867 const xtl::span<const std::uint32_t>&, std::int32_t,
869 dof_transform_to_transpose
870 = element1->get_dof_transformation_to_transpose_function<T>();
872 for (
int i : a.integral_ids(IntegralType::cell))
874 const auto& kernel = a.kernel(IntegralType::cell, i);
875 const std::vector<std::int32_t>& active_cells
876 = a.domains(IntegralType::cell, i);
877 if (bs0 == 1 and bs1 == 1)
879 _lift_bc_cells<T, 1, 1>(
880 b, mesh->geometry(), kernel, active_cells, dof_transform, dofmap0,
881 bs0, dof_transform_to_transpose, dofmap1, bs1, constants, coeffs,
882 cell_info, bc_values1, bc_markers1, x0, scale);
884 else if (bs0 == 3 and bs1 == 3)
886 _lift_bc_cells<T, 3, 3>(
887 b, mesh->geometry(), kernel, active_cells, dof_transform, dofmap0,
888 bs0, dof_transform_to_transpose, dofmap1, bs1, constants, coeffs,
889 cell_info, bc_values1, bc_markers1, x0, scale);
893 _lift_bc_cells(b, mesh->geometry(), kernel, active_cells, dof_transform,
894 dofmap0, bs0, dof_transform_to_transpose, dofmap1, bs1,
895 constants, coeffs, cell_info, bc_values1, bc_markers1, x0,
900 if (a.num_integrals(IntegralType::exterior_facet) > 0
901 or a.num_integrals(IntegralType::interior_facet) > 0)
904 mesh->topology_mutable().create_entities(tdim - 1);
905 mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
907 std::function<std::uint8_t(std::size_t)> get_perm;
908 if (a.needs_facet_permutations())
910 mesh->topology_mutable().create_entity_permutations();
911 const std::vector<std::uint8_t>& perms
912 = mesh->topology().get_facet_permutations();
913 get_perm = [&perms](std::size_t i) {
return perms[i]; };
916 get_perm = [](std::size_t) {
return 0; };
918 for (
int i : a.integral_ids(IntegralType::exterior_facet))
920 const auto& kernel = a.kernel(IntegralType::exterior_facet, i);
921 const std::vector<std::int32_t>& active_facets
922 = a.domains(IntegralType::exterior_facet, i);
923 _lift_bc_exterior_facets(b, *mesh, kernel, active_facets, dof_transform,
924 dofmap0, bs0, dof_transform_to_transpose,
925 dofmap1, bs1, constants, coeffs, cell_info,
926 get_perm, bc_values1, bc_markers1, x0, scale);
929 const std::vector<int> c_offsets = a.coefficient_offsets();
930 for (
int i : a.integral_ids(IntegralType::interior_facet))
932 const auto& kernel = a.kernel(IntegralType::interior_facet, i);
933 const std::vector<std::int32_t>& active_facets
934 = a.domains(IntegralType::interior_facet, i);
935 _lift_bc_interior_facets(
936 b, *mesh, kernel, active_facets, dof_transform, dofmap0, bs0,
937 dof_transform_to_transpose, dofmap1, bs1, constants, coeffs,
938 c_offsets, cell_info, get_perm, bc_values1, bc_markers1, x0, scale);
962 template <
typename T>
964 xtl::span<T> b,
const std::vector<std::shared_ptr<
const Form<T>>> a,
965 const std::vector<xtl::span<const T>>& constants,
966 const std::vector<
const array2d<T>*>& coeffs,
967 const std::vector<std::vector<std::shared_ptr<
const DirichletBC<T>>>>& bcs1,
968 const std::vector<xtl::span<const T>>& x0,
double scale)
971 if (!x0.empty() and x0.size() != a.size())
973 throw std::runtime_error(
974 "Mismatch in size between x0 and bilinear form in assembler.");
977 if (a.size() != bcs1.size())
979 throw std::runtime_error(
980 "Mismatch in size between a and bcs in assembler.");
983 for (std::size_t j = 0; j < a.size(); ++j)
985 std::vector<bool> bc_markers1;
986 std::vector<T> bc_values1;
987 if (a[j] and !bcs1[j].empty())
989 assert(a[j]->function_spaces().at(0));
991 auto V1 = a[j]->function_spaces()[1];
993 auto map1 = V1->dofmap()->index_map;
994 const int bs1 = V1->dofmap()->index_map_bs();
996 const int crange = bs1 * (map1->size_local() + map1->num_ghosts());
997 bc_markers1.assign(crange,
false);
998 bc_values1.assign(crange, 0.0);
999 for (
const std::shared_ptr<
const DirichletBC<T>>& bc : bcs1[j])
1001 bc->mark_dofs(bc_markers1);
1002 bc->dof_values(bc_values1);
1008 lift_bc<T>(b, *a[j], constants[j], *coeffs[j], bc_values1, bc_markers1,
1013 lift_bc<T>(b, *a[j], constants[j], *coeffs[j], bc_values1, bc_markers1,
1014 xtl::span<const T>(), scale);
1026 template <
typename T>
1028 const xtl::span<const T>& constants,
1029 const array2d<T>& coeffs)
1031 std::shared_ptr<const mesh::Mesh> mesh = L.mesh();
1033 const int tdim = mesh->topology().dim();
1036 assert(L.function_spaces().at(0));
1037 std::shared_ptr<const fem::FiniteElement> element
1038 = L.function_spaces().at(0)->element();
1039 std::shared_ptr<const fem::DofMap> dofmap
1040 = L.function_spaces().at(0)->dofmap();
1042 const graph::AdjacencyList<std::int32_t>& dofs = dofmap->list();
1043 const int bs = dofmap->bs();
1045 const std::function<void(
const xtl::span<T>&,
1046 const xtl::span<const std::uint32_t>&, std::int32_t,
1048 dof_transform = element->get_dof_transformation_function<T>();
1050 const bool needs_transformation_data
1051 = element->needs_dof_transformations() or L.needs_facet_permutations();
1052 xtl::span<const std::uint32_t> cell_info;
1053 if (needs_transformation_data)
1055 mesh->topology_mutable().create_entity_permutations();
1056 cell_info = xtl::span(mesh->topology().get_cell_permutation_info());
1059 for (
int i : L.integral_ids(IntegralType::cell))
1061 const auto& fn = L.kernel(IntegralType::cell, i);
1062 const std::vector<std::int32_t>& active_cells
1063 = L.domains(IntegralType::cell, i);
1066 impl::assemble_cells<T, 1>(dof_transform, b, mesh->geometry(),
1067 active_cells, dofs, bs, fn, constants, coeffs,
1072 impl::assemble_cells<T, 3>(dof_transform, b, mesh->geometry(),
1073 active_cells, dofs, bs, fn, constants, coeffs,
1078 impl::assemble_cells(dof_transform, b, mesh->geometry(), active_cells,
1079 dofs, bs, fn, constants, coeffs, cell_info);
1083 if (L.num_integrals(IntegralType::exterior_facet) > 0
1084 or L.num_integrals(IntegralType::interior_facet) > 0)
1087 mesh->topology_mutable().create_entities(tdim - 1);
1088 mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
1089 std::function<std::uint8_t(std::size_t)> get_perm;
1090 if (L.needs_facet_permutations())
1092 mesh->topology_mutable().create_entity_permutations();
1093 const std::vector<std::uint8_t>& perms
1094 = mesh->topology().get_facet_permutations();
1095 get_perm = [&perms](std::size_t i) {
return perms[i]; };
1098 get_perm = [](std::size_t) {
return 0; };
1100 for (
int i : L.integral_ids(IntegralType::exterior_facet))
1102 const auto& fn = L.kernel(IntegralType::exterior_facet, i);
1103 const std::vector<std::int32_t>& active_facets
1104 = L.domains(IntegralType::exterior_facet, i);
1107 impl::assemble_exterior_facets<T, 1>(
1108 dof_transform, b, *mesh, active_facets, dofs, bs, fn, constants,
1109 coeffs, cell_info, get_perm);
1113 impl::assemble_exterior_facets<T, 3>(
1114 dof_transform, b, *mesh, active_facets, dofs, bs, fn, constants,
1115 coeffs, cell_info, get_perm);
1119 impl::assemble_exterior_facets(dof_transform, b, *mesh, active_facets,
1120 dofs, bs, fn, constants, coeffs,
1121 cell_info, get_perm);
1125 const std::vector<int> c_offsets = L.coefficient_offsets();
1126 for (
int i : L.integral_ids(IntegralType::interior_facet))
1128 const auto& fn = L.kernel(IntegralType::interior_facet, i);
1129 const std::vector<std::int32_t>& active_facets
1130 = L.domains(IntegralType::interior_facet, i);
1133 impl::assemble_interior_facets<T, 1>(
1134 dof_transform, b, *mesh, active_facets, *dofmap, fn, constants,
1135 coeffs, c_offsets, cell_info, get_perm);
1139 impl::assemble_interior_facets<T, 3>(
1140 dof_transform, b, *mesh, active_facets, *dofmap, fn, constants,
1141 coeffs, c_offsets, cell_info, get_perm);
1145 impl::assemble_interior_facets(dof_transform, b, *mesh, active_facets,
1146 *dofmap, fn, constants, coeffs,
1147 c_offsets, cell_info, get_perm);
void cells(la::SparsityPattern &pattern, const mesh::Topology &topology, const std::array< const std::reference_wrapper< const fem::DofMap >, 2 > &dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition: sparsitybuild.cpp:18
void assemble_vector(xtl::span< T > b, const Form< T > &L, const xtl::span< const T > &constants, const array2d< T > &coeffs)
Assemble linear form into a vector, The caller supplies the form constants and coefficients for this ...
Definition: assembler.h:66
void apply_lifting(xtl::span< T > b, const std::vector< std::shared_ptr< const Form< T >>> &a, const std::vector< xtl::span< const T >> &constants, const std::vector< const array2d< T > * > &coeffs, const std::vector< std::vector< std::shared_ptr< const DirichletBC< T >>>> &bcs1, const std::vector< xtl::span< const T >> &x0, double scale)
Modify b such that:
Definition: assembler.h:104