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
42 xtl::span<T> b,
const mesh::Geometry& geometry,
43 const std::vector<std::int32_t>& active_cells,
44 const graph::AdjacencyList<std::int32_t>& dofmap,
const int bs,
45 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
46 const std::uint8_t*,
const std::uint32_t)>& kernel,
47 const array2d<T>& coeffs,
const std::vector<T>& constant_values,
48 const std::vector<std::uint32_t>& cell_info);
52 void assemble_exterior_facets(
53 xtl::span<T> b,
const mesh::Mesh& mesh,
54 const std::vector<std::int32_t>& active_facets,
55 const graph::AdjacencyList<std::int32_t>& dofmap,
const int bs,
56 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
57 const std::uint8_t*,
const std::uint32_t)>& fn,
58 const array2d<T>& coeffs,
const std::vector<T>& constant_values,
59 const std::vector<std::uint32_t>& cell_info,
60 const std::vector<std::uint8_t>& perms);
64 void assemble_interior_facets(
65 xtl::span<T> b,
const mesh::Mesh& mesh,
66 const std::vector<std::int32_t>& active_facets,
const fem::DofMap& dofmap,
67 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
68 const std::uint8_t*,
const std::uint32_t)>& fn,
69 const array2d<T>& coeffs,
const std::vector<int>& offsets,
70 const std::vector<T>& constant_values,
71 const std::vector<std::uint32_t>& cell_info,
72 const std::vector<std::uint8_t>& perms);
93 xtl::span<T> b,
const std::vector<std::shared_ptr<
const Form<T>>> a,
94 const std::vector<std::vector<std::shared_ptr<
const DirichletBC<T>>>>& bcs1,
95 const xtl::span<const T>& x0,
double scale);
109 template <
typename T>
110 void lift_bc(xtl::span<T> b,
const Form<T>& a,
111 const xtl::span<const T>& bc_values1,
112 const std::vector<bool>& bc_markers1,
const xtl::span<const T>& x0,
116 template <
typename T>
118 xtl::span<T> b,
const mesh::Geometry& geometry,
119 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
120 const std::uint8_t*,
const std::uint32_t)>& kernel,
121 const std::vector<std::int32_t>& active_cells,
122 const graph::AdjacencyList<std::int32_t>& dofmap0,
int bs0,
123 const graph::AdjacencyList<std::int32_t>& dofmap1,
int bs1,
124 const array2d<T>& coeffs,
const std::vector<T>& constant_values,
125 const std::vector<std::uint32_t>& cell_info,
126 const xtl::span<const T>& bc_values1,
const std::vector<bool>& bc_markers1,
127 const xtl::span<const T>& x0,
double scale)
130 const std::size_t gdim = geometry.dim();
131 const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
134 const std::size_t num_dofs_g = x_dofmap.num_links(0);
135 const xt::xtensor<double, 2>& x_g = geometry.x();
138 std::vector<double> coordinate_dofs(num_dofs_g * gdim);
139 std::vector<T> Ae, be;
141 for (std::int32_t c : active_cells)
144 auto dmap1 = dofmap1.links(c);
148 for (std::size_t j = 0; j < dmap1.size(); ++j)
150 for (
int k = 0; k < bs1; ++k)
152 assert(bs1 * dmap1[j] + k < (
int)bc_markers1.size());
153 if (bc_markers1[bs1 * dmap1[j] + k])
165 auto x_dofs = x_dofmap.links(c);
166 for (std::size_t i = 0; i < x_dofs.size(); ++i)
168 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), gdim,
169 std::next(coordinate_dofs.begin(), i * gdim));
173 auto dmap0 = dofmap0.links(c);
175 const int num_rows = bs0 * dmap0.size();
176 const int num_cols = bs1 * dmap1.size();
178 auto coeff_array = coeffs.row(c);
179 Ae.resize(num_rows * num_cols);
180 std::fill(Ae.begin(), Ae.end(), 0);
181 kernel(Ae.data(), coeff_array.data(), constant_values.data(),
182 coordinate_dofs.data(),
nullptr,
nullptr, cell_info[c]);
186 std::fill(be.begin(), be.end(), 0);
187 for (std::size_t j = 0; j < dmap1.size(); ++j)
189 for (
int k = 0; k < bs1; ++k)
191 const std::int32_t jj = bs1 * dmap1[j] + k;
192 assert(jj < (
int)bc_markers1.size());
195 const T bc = bc_values1[jj];
196 const T _x0 = x0.empty() ? 0.0 : x0[jj];
198 for (
int m = 0; m < num_rows; ++m)
199 be[m] -= Ae[m * num_cols + bs1 * j + k] * scale * (bc - _x0);
204 for (std::size_t i = 0; i < dmap0.size(); ++i)
205 for (
int k = 0; k < bs0; ++k)
206 b[bs0 * dmap0[i] + k] += be[bs0 * i + k];
210 template <
typename T>
211 void _lift_bc_exterior_facets(
212 xtl::span<T> b,
const mesh::Mesh& mesh,
213 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
214 const std::uint8_t*,
const std::uint32_t)>& kernel,
215 const std::vector<std::int32_t>& active_facets,
216 const graph::AdjacencyList<std::int32_t>& dofmap0,
int bs0,
217 const graph::AdjacencyList<std::int32_t>& dofmap1,
int bs1,
218 const array2d<T>& coeffs,
const std::vector<T>& constant_values,
219 const std::vector<std::uint32_t>& cell_info,
220 const std::vector<std::uint8_t>& perms,
221 const xtl::span<const T>& bc_values1,
const std::vector<bool>& bc_markers1,
222 const xtl::span<const T>& x0,
double scale)
224 const std::size_t gdim = mesh.geometry().dim();
225 const int tdim = mesh.topology().dim();
228 const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
231 const std::size_t num_dofs_g = x_dofmap.num_links(0);
232 const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
235 std::vector<double> coordinate_dofs(num_dofs_g * gdim);
236 std::vector<T> Ae, be;
239 const mesh::Topology& topology = mesh.topology();
240 auto connectivity = topology.connectivity(tdim - 1, tdim);
241 assert(connectivity);
242 auto c_to_f = topology.connectivity(tdim, tdim - 1);
244 auto map = topology.index_map(tdim - 1);
247 for (std::int32_t f : active_facets)
250 assert(connectivity->num_links(f) == 1);
251 const std::int32_t cell = connectivity->links(f)[0];
254 auto facets = c_to_f->links(cell);
255 auto it = std::find(facets.begin(), facets.end(), f);
256 assert(it != facets.end());
257 const int local_facet = std::distance(facets.begin(), it);
260 auto dmap1 = dofmap1.links(cell);
264 for (std::size_t j = 0; j < dmap1.size(); ++j)
266 for (
int k = 0; k < bs1; ++k)
268 if (bc_markers1[bs1 * dmap1[j] + k])
280 auto x_dofs = x_dofmap.links(cell);
281 for (std::size_t i = 0; i < x_dofs.size(); ++i)
283 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), gdim,
284 std::next(coordinate_dofs.begin(), i * gdim));
288 auto dmap0 = dofmap0.links(cell);
290 const int num_rows = bs0 * dmap0.size();
291 const int num_cols = bs1 * dmap1.size();
293 auto coeff_array = coeffs.row(cell);
294 Ae.resize(num_rows * num_cols);
295 std::fill(Ae.begin(), Ae.end(), 0);
296 kernel(Ae.data(), coeff_array.data(), constant_values.data(),
297 coordinate_dofs.data(), &local_facet,
298 &perms[cell * facets.size() + local_facet], cell_info[cell]);
302 std::fill(be.begin(), be.end(), 0);
303 for (std::size_t j = 0; j < dmap1.size(); ++j)
305 for (
int k = 0; k < bs1; ++k)
307 const std::int32_t jj = bs1 * dmap1[j] + k;
311 const T bc = bc_values1[jj];
312 const T _x0 = x0.empty() ? 0.0 : x0[jj];
314 for (
int m = 0; m < num_rows; ++m)
315 be[m] -= Ae[m * num_cols + bs1 * j + k] * scale * (bc - _x0);
320 for (std::size_t i = 0; i < dmap0.size(); ++i)
321 for (
int k = 0; k < bs0; ++k)
322 b[bs0 * dmap0[i] + k] += be[bs0 * i + k];
326 template <
typename T>
327 void _lift_bc_interior_facets(
328 xtl::span<T> b,
const mesh::Mesh& mesh,
329 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
330 const std::uint8_t*,
const std::uint32_t)>& kernel,
331 const std::vector<std::int32_t>& active_facets,
332 const graph::AdjacencyList<std::int32_t>& dofmap0,
int bs0,
333 const graph::AdjacencyList<std::int32_t>& dofmap1,
int bs1,
334 const array2d<T>& coeffs,
const std::vector<int>& offsets,
335 const std::vector<T>& constant_values,
336 const std::vector<std::uint32_t>& cell_info,
337 const std::vector<std::uint8_t>& perms,
338 const xtl::span<const T>& bc_values1,
const std::vector<bool>& bc_markers1,
339 const xtl::span<const T>& x0,
double scale)
341 const std::size_t gdim = mesh.geometry().dim();
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, gdim});
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(), gdim,
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(), gdim,
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{perms[
cells[0] * facets_per_cell + local_facet[0]],
471 perms[
cells[1] * facets_per_cell + local_facet[1]]};
472 kernel(Ae.data(), coeff_array.data(), constant_values.data(),
473 coordinate_dofs.data(), local_facet.data(), perm.data(),
474 cell_info[cells[0]]);
477 std::fill(be.begin(), be.end(), 0);
480 for (std::size_t j = 0; j < dmap1_cell0.size(); ++j)
482 for (
int k = 0; k < bs1; ++k)
484 const std::int32_t jj = bs1 * dmap1_cell0[j] + k;
487 const T bc = bc_values1[jj];
488 const T _x0 = x0.empty() ? 0.0 : x0[jj];
490 for (
int m = 0; m < num_rows; ++m)
491 be[m] -= Ae[m * num_cols + bs1 * j + k] * scale * (bc - _x0);
497 const int offset = bs1 * dmap1_cell0.size();
498 for (std::size_t j = 0; j < dmap1_cell1.size(); ++j)
500 for (
int k = 0; k < bs1; ++k)
502 const std::int32_t jj = bs1 * dmap1_cell1[j] + k;
505 const T bc = bc_values1[jj];
506 const T _x0 = x0.empty() ? 0.0 : x0[jj];
508 for (
int m = 0; m < num_rows; ++m)
511 -= Ae[m * num_cols + offset + bs1 * j + k] * scale * (bc - _x0);
517 for (std::size_t i = 0; i < dmap0_cell0.size(); ++i)
518 for (
int k = 0; k < bs0; ++k)
519 b[bs0 * dmap0_cell0[i] + k] += be[bs0 * i + k];
521 for (std::size_t i = 0; i < dmap0_cell1.size(); ++i)
522 for (
int k = 0; k < bs0; ++k)
523 b[bs0 * dmap0_cell1[i] + k] += be[offset + bs0 * i + k];
527 template <
typename T>
530 std::shared_ptr<const mesh::Mesh> mesh = L.mesh();
532 const int tdim = mesh->topology().dim();
533 const std::int32_t num_cells
534 = mesh->topology().connectivity(tdim, 0)->num_nodes();
537 assert(L.function_spaces().at(0));
538 std::shared_ptr<const fem::DofMap> dofmap
539 = L.function_spaces().at(0)->dofmap();
541 const graph::AdjacencyList<std::int32_t>& dofs = dofmap->list();
542 const int bs = dofmap->bs();
550 const bool needs_permutation_data = L.needs_permutation_data();
551 if (needs_permutation_data)
552 mesh->topology_mutable().create_entity_permutations();
553 const std::vector<std::uint32_t>& cell_info
554 = needs_permutation_data ? mesh->topology().get_cell_permutation_info()
555 : std::vector<std::uint32_t>(num_cells);
557 for (
int i : L.integral_ids(IntegralType::cell))
559 const auto& fn = L.kernel(IntegralType::cell, i);
560 const std::vector<std::int32_t>& active_cells
561 = L.domains(IntegralType::cell, i);
562 fem::impl::assemble_cells(b, mesh->geometry(), active_cells, dofs, bs, fn,
563 coeffs, constant_values, cell_info);
566 if (L.num_integrals(IntegralType::exterior_facet) > 0
567 or L.num_integrals(IntegralType::interior_facet) > 0)
570 mesh->topology_mutable().create_entities(tdim - 1);
571 mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
572 mesh->topology_mutable().create_entity_permutations();
574 const std::vector<std::uint8_t>& perms
575 = mesh->topology().get_facet_permutations();
576 for (
int i : L.integral_ids(IntegralType::exterior_facet))
578 const auto& fn = L.kernel(IntegralType::exterior_facet, i);
579 const std::vector<std::int32_t>& active_facets
580 = L.domains(IntegralType::exterior_facet, i);
581 fem::impl::assemble_exterior_facets(b, *mesh, active_facets, dofs, bs, fn,
582 coeffs, constant_values, cell_info,
586 const std::vector<int> c_offsets = L.coefficient_offsets();
587 for (
int i : L.integral_ids(IntegralType::interior_facet))
589 const auto& fn = L.kernel(IntegralType::interior_facet, i);
590 const std::vector<std::int32_t>& active_facets
591 = L.domains(IntegralType::interior_facet, i);
592 fem::impl::assemble_interior_facets(b, *mesh, active_facets, *dofmap, fn,
593 coeffs, c_offsets, constant_values,
599 template <
typename T>
601 xtl::span<T> b,
const mesh::Geometry& geometry,
602 const std::vector<std::int32_t>& active_cells,
603 const graph::AdjacencyList<std::int32_t>& dofmap,
const int bs,
604 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
605 const std::uint8_t*,
const std::uint32_t)>& kernel,
606 const array2d<T>& coeffs,
const std::vector<T>& constant_values,
607 const std::vector<std::uint32_t>& cell_info)
609 const std::size_t gdim = geometry.dim();
612 const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
615 const int num_dofs_g = x_dofmap.num_links(0);
616 const xt::xtensor<double, 2>& x_g = geometry.x();
620 const int num_dofs = dofmap.links(0).size();
621 std::vector<double> coordinate_dofs(num_dofs_g * gdim);
622 std::vector<T> be(bs * num_dofs);
625 for (std::int32_t c : active_cells)
628 auto x_dofs = x_dofmap.links(c);
629 for (std::size_t i = 0; i < x_dofs.size(); ++i)
631 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), gdim,
632 std::next(coordinate_dofs.begin(), i * gdim));
636 std::fill(be.begin(), be.end(), 0);
637 kernel(be.data(), coeffs.row(c).data(), constant_values.data(),
638 coordinate_dofs.data(),
nullptr,
nullptr, cell_info[c]);
641 auto dofs = dofmap.links(c);
642 for (
int i = 0; i < num_dofs; ++i)
643 for (
int k = 0; k < bs; ++k)
644 b[bs * dofs[i] + k] += be[bs * i + k];
648 template <
typename T>
649 void assemble_exterior_facets(
650 xtl::span<T> b,
const mesh::Mesh& mesh,
651 const std::vector<std::int32_t>& active_facets,
652 const graph::AdjacencyList<std::int32_t>& dofmap,
const int bs,
653 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
654 const std::uint8_t*,
const std::uint32_t)>& fn,
655 const array2d<T>& coeffs,
const std::vector<T>& constant_values,
656 const std::vector<std::uint32_t>& cell_info,
657 const std::vector<std::uint8_t>& perms)
659 const std::size_t gdim = mesh.geometry().dim();
660 const int tdim = mesh.topology().dim();
663 const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
666 const std::size_t num_dofs_g = x_dofmap.num_links(0);
667 const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
671 const int num_dofs = dofmap.links(0).size();
672 std::vector<double> coordinate_dofs(num_dofs_g * gdim);
673 std::vector<T> be(bs * num_dofs);
675 auto f_to_c = mesh.topology().connectivity(tdim - 1, tdim);
677 auto c_to_f = mesh.topology().connectivity(tdim, tdim - 1);
679 for (std::int32_t f : active_facets)
682 assert(f_to_c->num_links(f) > 0);
683 const std::int32_t cell = f_to_c->links(f)[0];
686 auto facets = c_to_f->links(cell);
687 auto it = std::find(facets.begin(), facets.end(), f);
688 assert(it != facets.end());
689 const int local_facet = std::distance(facets.begin(), it);
692 auto x_dofs = x_dofmap.links(cell);
693 for (std::size_t i = 0; i < x_dofs.size(); ++i)
695 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), gdim,
696 std::next(coordinate_dofs.begin(), i * gdim));
700 std::fill(be.begin(), be.end(), 0);
701 fn(be.data(), coeffs.row(cell).data(), constant_values.data(),
702 coordinate_dofs.data(), &local_facet,
703 &perms[cell * facets.size() + local_facet], cell_info[cell]);
706 auto dofs = dofmap.links(cell);
707 for (
int i = 0; i < num_dofs; ++i)
708 for (
int k = 0; k < bs; ++k)
709 b[bs * dofs[i] + k] += be[bs * i + k];
713 template <
typename T>
714 void assemble_interior_facets(
715 xtl::span<T> b,
const mesh::Mesh& mesh,
716 const std::vector<std::int32_t>& active_facets,
const fem::DofMap& dofmap,
717 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
718 const std::uint8_t*,
const std::uint32_t)>& fn,
719 const array2d<T>& coeffs,
const std::vector<int>& offsets,
720 const std::vector<T>& constant_values,
721 const std::vector<std::uint32_t>& cell_info,
722 const std::vector<std::uint8_t>& perms)
724 const std::size_t gdim = mesh.geometry().dim();
725 const int tdim = mesh.topology().dim();
728 const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
731 const std::size_t num_dofs_g = x_dofmap.num_links(0);
732 const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
735 xt::xtensor<double, 3> coordinate_dofs({2, num_dofs_g, gdim});
737 std::vector<T> coeff_array(2 * offsets.back());
738 assert(offsets.back() ==
int(coeffs.shape[1]));
740 const int bs = dofmap.bs();
741 auto f_to_c = mesh.topology().connectivity(tdim - 1, tdim);
743 auto c_to_f = mesh.topology().connectivity(tdim, tdim - 1);
745 for (std::int32_t f : active_facets)
748 auto cells = f_to_c->links(f);
749 assert(
cells.size() == 2);
751 const int facets_per_cell = c_to_f->num_links(cells[0]);
754 std::array<int, 2> local_facet;
755 for (
int i = 0; i < 2; ++i)
757 auto facets = c_to_f->links(cells[i]);
758 auto it = std::find(facets.begin(), facets.end(), f);
759 assert(it != facets.end());
760 local_facet[i] = std::distance(facets.begin(), it);
764 auto x_dofs0 = x_dofmap.links(cells[0]);
765 for (std::size_t i = 0; i < x_dofs0.size(); ++i)
767 std::copy_n(xt::view(x_g, x_dofs0[i]).begin(), gdim,
768 xt::view(coordinate_dofs, 0, i, xt::all()).begin());
770 auto x_dofs1 = x_dofmap.links(cells[1]);
771 for (std::size_t i = 0; i < x_dofs1.size(); ++i)
773 std::copy_n(xt::view(x_g, x_dofs1[i]).begin(), gdim,
774 xt::view(coordinate_dofs, 1, i, xt::all()).begin());
779 auto coeff_cell0 = coeffs.row(cells[0]);
780 auto coeff_cell1 = coeffs.row(cells[1]);
783 for (std::size_t i = 0; i < offsets.size() - 1; ++i)
786 const int num_entries = offsets[i + 1] - offsets[i];
787 std::copy_n(coeff_cell0.data() + offsets[i], num_entries,
788 std::next(coeff_array.begin(), 2 * offsets[i]));
789 std::copy_n(coeff_cell1.data() + offsets[i], num_entries,
790 std::next(coeff_array.begin(), offsets[i + 1] + offsets[i]));
794 xtl::span<const std::int32_t> dmap0 = dofmap.cell_dofs(cells[0]);
795 xtl::span<const std::int32_t> dmap1 = dofmap.cell_dofs(cells[1]);
798 be.resize(bs * (dmap0.size() + dmap1.size()));
799 std::fill(be.begin(), be.end(), 0);
800 const std::array perm{perms[
cells[0] * facets_per_cell + local_facet[0]],
801 perms[
cells[1] * facets_per_cell + local_facet[1]]};
802 fn(be.data(), coeff_array.data(), constant_values.data(),
803 coordinate_dofs.data(), local_facet.data(), perm.data(),
804 cell_info[cells[0]]);
807 for (std::size_t i = 0; i < dmap0.size(); ++i)
808 for (
int k = 0; k < bs; ++k)
809 b[bs * dmap0[i] + k] += be[bs * i + k];
810 for (std::size_t i = 0; i < dmap1.size(); ++i)
811 for (
int k = 0; k < bs; ++k)
812 b[bs * dmap1[i] + k] += be[bs * (i + dmap0.size()) + k];
816 template <
typename T>
818 xtl::span<T> b,
const std::vector<std::shared_ptr<
const Form<T>>> a,
819 const std::vector<std::vector<std::shared_ptr<
const DirichletBC<T>>>>& bcs1,
820 const std::vector<xtl::span<const T>>& x0,
double scale)
823 if (!x0.empty() and x0.size() != a.size())
825 throw std::runtime_error(
826 "Mismatch in size between x0 and bilinear form in assembler.");
829 if (a.size() != bcs1.size())
831 throw std::runtime_error(
832 "Mismatch in size between a and bcs in assembler.");
835 for (std::size_t j = 0; j < a.size(); ++j)
837 std::vector<bool> bc_markers1;
838 std::vector<T> bc_values1;
839 if (a[j] and !bcs1[j].empty())
841 auto V1 = a[j]->function_spaces()[1];
843 auto map1 = V1->dofmap()->index_map;
844 const int bs1 = V1->dofmap()->index_map_bs();
846 const int crange = bs1 * (map1->size_local() + map1->num_ghosts());
847 bc_markers1.assign(crange,
false);
848 bc_values1.assign(crange, 0.0);
849 for (
const std::shared_ptr<
const DirichletBC<T>>& bc : bcs1[j])
851 bc->mark_dofs(bc_markers1);
852 bc->dof_values(bc_values1);
856 lift_bc<T>(b, *a[j], bc_values1, bc_markers1, x0[j], scale);
859 lift_bc<T>(b, *a[j], bc_values1, bc_markers1, xtl::span<const T>(),
866 template <
typename T>
867 void lift_bc(xtl::span<T> b,
const Form<T>& a,
868 const xtl::span<const T>& bc_values1,
869 const std::vector<bool>& bc_markers1,
const xtl::span<const T>& x0,
872 std::shared_ptr<const mesh::Mesh> mesh = a.mesh();
874 const int tdim = mesh->topology().dim();
875 const std::int32_t num_cells
876 = mesh->topology().connectivity(tdim, 0)->num_nodes();
879 assert(a.function_spaces().at(0));
880 assert(a.function_spaces().at(1));
881 const graph::AdjacencyList<std::int32_t>& dofmap0
882 = a.function_spaces()[0]->dofmap()->list();
883 const int bs0 = a.function_spaces()[0]->dofmap()->bs();
884 const graph::AdjacencyList<std::int32_t>& dofmap1
885 = a.function_spaces()[1]->dofmap()->list();
886 const int bs1 = a.function_spaces()[1]->dofmap()->bs();
894 const bool needs_permutation_data = a.needs_permutation_data();
895 if (needs_permutation_data)
896 mesh->topology_mutable().create_entity_permutations();
897 const std::vector<std::uint32_t>& cell_info
898 = needs_permutation_data ? mesh->topology().get_cell_permutation_info()
899 : std::vector<std::uint32_t>(num_cells);
901 for (
int i : a.integral_ids(IntegralType::cell))
903 const auto& kernel = a.kernel(IntegralType::cell, i);
904 const std::vector<std::int32_t>& active_cells
905 = a.domains(IntegralType::cell, i);
906 _lift_bc_cells(b, mesh->geometry(), kernel, active_cells, dofmap0, bs0,
907 dofmap1, bs1, coeffs, constant_values, cell_info, bc_values1,
908 bc_markers1, x0, scale);
911 if (a.num_integrals(IntegralType::exterior_facet) > 0
912 or a.num_integrals(IntegralType::interior_facet) > 0)
915 mesh->topology_mutable().create_entities(tdim - 1);
916 mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
917 mesh->topology_mutable().create_entity_permutations();
919 const std::vector<std::uint8_t>& perms
920 = mesh->topology().get_facet_permutations();
921 for (
int i : a.integral_ids(IntegralType::exterior_facet))
923 const auto& kernel = a.kernel(IntegralType::exterior_facet, i);
924 const std::vector<std::int32_t>& active_facets
925 = a.domains(IntegralType::exterior_facet, i);
926 _lift_bc_exterior_facets(b, *mesh, kernel, active_facets, dofmap0, bs0,
927 dofmap1, bs1, coeffs, constant_values, cell_info,
928 perms, bc_values1, bc_markers1, x0, scale);
931 const std::vector<int> c_offsets = a.coefficient_offsets();
932 for (
int i : a.integral_ids(IntegralType::interior_facet))
934 const auto& kernel = a.kernel(IntegralType::interior_facet, i);
935 const std::vector<std::int32_t>& active_facets
936 = a.domains(IntegralType::interior_facet, i);
937 _lift_bc_interior_facets(b, *mesh, kernel, active_facets, dofmap0, bs0,
938 dofmap1, bs1, coeffs, c_offsets, constant_values,
939 cell_info, perms, bc_values1, bc_markers1, x0,